zoukankan      html  css  js  c++  java
  • Java的多线程

        Java使用Thread代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用就是执行一段程序流(完成一定的任务)。

    Java使用线程执行体来代表这段程序流。

     1. 继承Thread类创建线程类

    package org.apache;
    
    public class ThreadDemo1 extends Thread {
    	private int i;
    	/*
    	 * 重写run方法,也就是线程执行体
    	 * 当线程类继承Thread类时,直接使用this即可取得当前线程
    	 * 直接调用getName()方法即可返回当前线程的名字
    	 */
    	public void run(){
    		for ( ; i<100;i++){
    			System.out.println(getName() + " " + i);
    		}
    	}
    	
    	public static void main(String[] args) 
    	{
    		for (int i=0;i<100;i++){
    			System.out.println(Thread.currentThread().getName() 
    					+ " "+i);
    			if(i==20){
    				//创建并启动第一个线程
    				new ThreadDemo1().start();
    				//创建并启动第二个线程
    				new ThreadDemo1().start();
    			}
    		}
    	}
    }
    

      执行结果:

    注意:实际上该程序有三个线程,main()方法是主线程,显示的创建了两个子线程。

       Thread-0和Thread-1 i的值是不连续的,所以Thread-0和Thread-1不能共享Thread类的实例变量。

    2. 实现Runnable接口创建线程类

    package org.apache;
    
    public class ThreadDemo2 implements Runnable {
    	private int i;
    	//当实现Runnable接口时必须用Thread.currentThread().getName()获取当前线程
    	public void run() {
    		for ( ; i<100;i++){
    			System.out.println(Thread.currentThread().getName() + " " + i);
    		}
    	}
    
    	public static void main(String[] args) {
    		for (int i=0;i<100;i++){
    			System.out.println(Thread.currentThread().getName() + " "+i);
    			if (i==20){
    				ThreadDemo2 td = new ThreadDemo2();
    				//通过new Thread(target,name)方法创建线程
    				new Thread(td,"线程1").start();
    				new Thread(td,"线程2").start();
    			}
    		}
    
    	}
    }
    

      结果:

    i的值是连续的,共享同一个线程类的实例变量(其实是线程的target类)

    3.使用Callable和Future创建线程

    FutureTask同时实现

    Future接口--->接收call()方法的返回值

    和Runnable接口--->可以作为Thread的target

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /*
     * 创建并启动有返回值的线程步骤:
     * 1. 创建Callable接口的实现类,并实现call()方法,作为线程执行体
     * 2. 使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的call()方法
     * 3. 使用FutureTask对象作为Thread对象的target创建并启动新线程
     * 4. 调用FutureTask对象的get()方法获得子线程的执行结束的返回值
     */
    public class ThreadDemo3 implements Callable{
    	private int i;
    	
    	public Object call() throws Exception {
    		for ( ; i<100;i++){
    			System.out.println(Thread.currentThread().getName() + " " + i);
    		}
    		return i;
    	}
    
    	public static void main(String[] args) {
    		ThreadDemo3 td = new ThreadDemo3();
    		//通过new Thread(target,name)方法创建线程
    		FutureTask<Integer> task = new  FutureTask<Integer>(td);
    		for (int i=0;i<100;i++){
    			System.out.println(Thread.currentThread().getName() + " "+i);
    			if (i==20){
    				new Thread(task,"有返回值的线程").start();
    			}
    		}
    		try {
                  //获取线程返回值 System.out.println(task.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }

      结果:

    4. 控制线程

    4.1 join线程

    当程序程序执行流中调用其它线程的join()方法时,调用线程将会被阻塞。直到被join的线程执行完成。

    package org.apache;
    
    public class ThreadDemo1 extends Thread {
    	public ThreadDemo1 (String name){
    		super(name);
    	}
    	private int i;
    	/*
    	 * 重写run方法,也就是线程执行体
    	 * 当线程类继承Thread类时,直接使用this即可取得当前线程
    	 * 直接调用getName()方法即可返回当前线程的名字
    	 */
    	public void run(){
    		for ( ; i<100;i++){
    			System.out.println(getName() + " " + i);
    		}
    	}
    	
    	public static void main(String[] args) throws InterruptedException 
    	{
    		new ThreadDemo1("新线程").start();
    		for (int i=0;i<100;i++){
    			Thread task = new ThreadDemo1("被join的线程");
    			System.out.println(Thread.currentThread().getName() 
    					+ " "+i);
    			if(i==20){
    				//创建并启动第一个线程
    				task.start();
    				//main调用了join()方法,必须等task执行结束后才会向下执行
    				task.join();
    			}
    		}
    	}
    }
    

      

      执行结果:

     分析可知main方法(主线程)被阻塞,只有新线程和join线程并发执行。

    4.2 守护线程

    有一种线程是为其它线程提供服务的(典型的有GC),被称为后台线程或者守护线程。

    package org.apache;
    
    public class ThreadDemo4 extends Thread{
    	private int i;
    	public void run(){
    		for (;i<1000;i++){
    			System.out.println(getName() + " "+i);
    		}
    	}
    
    	public static void main(String[] args) {
    		ThreadDemo4 task = new ThreadDemo4();
    		//设置为守护进程
    		task.setDaemon(true);
    		task.start();
    		for( int i=0;i<10;i++){
    			System.out.println(Thread.currentThread().getName()+" "+i);
    		}
    		//程序执行到此处就main进程就结束了,JVM将会主动退出,守护线程也将被结束,无法执行到=999
    	}
    }
    

     执行结果: 

    4.3 线程睡眠:sleep
    package org.apache;
    
    import java.util.Date;
    
    public class ThreadDemo5 {
          //正在执行的线程将会暂停一段时间,进入阻塞状态
    	public static void main(String[] args) throws InterruptedException {
    		for (int i=0;i<10;i++){
    			System.out.println("当前时间: "+new Date());
    			Thread.sleep(1000);
    		}
    	}
    }
    

      结果:

  • 相关阅读:
    css定位
    题解 P2345 【奶牛集会】
    浅谈主席树
    浅谈Manacher算法
    CSP2019 游记
    P5025 [SNOI2017]炸弹
    浅谈2-SAT
    DAY 5模拟赛
    DAY 3
    Luogu P2915 [USACO08NOV]奶牛混合起来
  • 原文地址:https://www.cnblogs.com/zydev/p/6821402.html
Copyright © 2011-2022 走看看