[JAVA修炼之路三]-JAVA Thread 方法

一、sleep与wait方法区别
       1、这两个方法来自不同的类分别是Thread和Object
       2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
       3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
    	任何地方使用
  	 synchronized(x){
      		x.notify()
     		//或者wait()
   	}
       4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
二、daemon方法
java中的后台线程,是Thread实例设置了setDaemon(true),即将daemon属性设置为了true。 
1、当程序中没有活动的前台线程时,后台线程会被jvm中断,退出程序,这是后台线程和普通线程的唯一区别。
2、需要注意将线程设置为daemon的时机,必须在其运行之前。
三、join方法

1、使用方式。

join是Thread类的一个方法,启动线程后直接调用,例如:

?
1
Thread t =  new AThread(); t.start(); t.join();

2、为什么要用join()方法

在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

3、join方法的作用

在JDk的API里对于join()方法是:

join

public final void join() throws InterruptedException Waits for this thread to die. Throws: InterruptedException  - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。

4、用实例来理解

写一个简单的例子来看一下join()的用法:

1.AThread 类

  1. BThread类

  2. TestDemo 类

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    class BThread  extends Thread {
         public BThread() {
             super ( "[BThread] Thread" );
         };
         public void run() {
             String threadName = Thread.currentThread().getName();
             System.out.println(threadName +  " start." );
             try {
                 for ( int i =  0 ; i <  5 ; i++) {
                     System.out.println(threadName +  " loop at " + i);
                     Thread.sleep( 1000 );
                 }
                 System.out.println(threadName +  " end." );
             catch (Exception e) {
                 System.out.println( "Exception from " + threadName +  ".run" );
             }
         }
    }
    class AThread  extends Thread {
         BThread bt;
         public AThread(BThread bt) {
             super ( "[AThread] Thread" );
             this .bt = bt;
         }
         public void run() {
             String threadName = Thread.currentThread().getName();
             System.out.println(threadName +  " start." );
             try {
                 bt.join();
                 System.out.println(threadName +  " end." );
             catch (Exception e) {
                 System.out.println( "Exception from " + threadName +  ".run" );
             }
         }
    }
    public class TestDemo {
         public static void main(String[] args) {
             String threadName = Thread.currentThread().getName();
             System.out.println(threadName +  " start." );
             BThread bt =  new BThread();
             AThread at =  new AThread(bt);
             try {
                 bt.start();
                 Thread.sleep( 2000 );
                 at.start();
                 at.join();
             catch (Exception e) {
                 System.out.println( "Exception from main" );
             }
             System.out.println(threadName +  " end!" );
         }
    }

    打印结果:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    main start.     // 主线程起动,因为调用了at. join (),要等到at结束了,此线程才能向下执行。
    [BThread] Thread start.
    [BThread] Thread loop at 0
    [BThread] Thread loop at 1
    [AThread] Thread start.     // 线程at启动,因为调用bt. join (),等到bt结束了才向下执行。
    [BThread] Thread loop at 2
    [BThread] Thread loop at 3
    [BThread] Thread loop at 4
    [BThread] Thread end.
    [AThread] Thread end.     // 线程AThread在bt. join ();阻塞处起动,向下继续执行的结果
    main end!       // 线程AThread结束,此线程在at. join ();阻塞处起动,向下继续执行的结果。
    修改一下代码:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class TestDemo {
         public static void main(String[] args) {
             String threadName = Thread.currentThread().getName();
             System.out.println(threadName +  " start." );
             BThread bt =  new BThread();
             AThread at =  new AThread(bt);
             try {
                 bt.start();
                 Thread.sleep( 2000 );
                 at.start();
                 //at.join(); //在此处注释掉对join()的调用
             catch (Exception e) {
                 System.out.println( "Exception from main" );
             }
             System.out.println(threadName +  " end!" );
         }
    }

    打印结果:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    main start.     // 主线程起动,因为Thread. sleep (2000),主线程没有马上结束;
     
    [BThread] Thread start.     // 线程BThread起动
    [BThread] Thread loop at 0
    [BThread] Thread loop at 1
    main end!    // sleep 两秒后主线程结束,AThread执行的bt. join ();并不会影响到主线程。
    [AThread] Thread start.     // 线程at起动,因为调用了bt. join (),等到bt结束了,此线程才向下执行。
    [BThread] Thread loop at 2
    [BThread] Thread loop at 3
    [BThread] Thread loop at 4
    [BThread] Thread end.     // 线程BThread结束了
    [AThread] Thread end.     // 线程AThread在bt. join ();阻塞处起动,向下继续执行的结果

    5、从源码看join()方法

    在AThread的run方法里,执行了bt.join();,进入看一下它的JDK源码:

    ?
    1
    2
    3
    public final void join()  throws InterruptedException {
         join(0L);
    }
    然后进入join(0L)方法:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public final synchronized void join( long l)
         throws InterruptedException
    {
         long l1 = System.currentTimeMillis();
         long l2 = 0L;
         if (l < 0L)
             throw new IllegalArgumentException( "timeout value is negative" );
         if (l == 0L)
             for (; isAlive(); wait(0L));
         else
             do
             {
                 if (!isAlive())
                     break ;
                 long l3 = l - l2;
                 if (l3 <= 0L)
                     break ;
                 wait(l3);
                 l2 = System.currentTimeMillis() - l1;
             while ( true );
    }

    单纯从代码上看: * 如果线程被生成了,但还未被起动,isAlive()将返回false,调用它的join()方法是没有作用的。将直接继续向下执行。 * 在AThread类中的run方法中,bt.join()是判断bt的active状态,如果bt的isActive()方法返回false,在bt.join(),这一点就不用阻塞了,可以继续向下进行了。从源码里看,wait方法中有参数,也就是不用唤醒谁,只是不再执行wait,向下继续执行而已。 * 在join()方法中,对于isAlive()和wait()方法的作用对象是个比较让人困惑的问题:

    isAlive()方法的签名是:public final native boolean isAlive(),也就是说isAlive()是判断当前线程的状态,也就是bt的状态。

    wait()方法在jdk文档中的解释如下:

    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

    在这里,当前线程指的是at。

四、yield方法

  调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

  注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

 六、interrupt方法

  interrupt,顾名思义,即中断的意思。单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,也就说,它可以用来中断一个正处于阻塞状态的线程;另外,通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

  下面看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public  class  Test {
     
     public  static  void  main(String[] args)  throws  IOException  {
         Test test =  new  Test();
         MyThread thread = test. new  MyThread();
         thread.start();
         try  {
             Thread.currentThread().sleep( 2000 );
         catch  (InterruptedException e) {
             
         }
         thread.interrupt();
    
     
     class  MyThread  extends  Thread{
         @Override
         public  void  run() {
             try  {
                 System.out.println( "进入睡眠状态" );
                 Thread.currentThread().sleep( 10000 );
                 System.out.println( "睡眠完毕" );
             catch  (InterruptedException e) {
                 System.out.println( "得到中断异常" );
             }
             System.out.println( "run方法执行完毕" );
         }
     }
}

   输出结果:

  

  从这里可以看出,通过interrupt方法可以中断处于阻塞状态的线程。那么能不能中断处于非阻塞状态的线程呢?看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  Test {
     
     public  static  void  main(String[] args)  throws  IOException  {
         Test test =  new  Test();
         MyThread thread = test. new  MyThread();
         thread.start();
         try  {
             Thread.currentThread().sleep( 2000 );
         catch  (InterruptedException e) {
             
         }
         thread.interrupt();
    
     
     class  MyThread  extends  Thread{
         @Override
         public  void  run() {
             int  i =  0 ;
             while (i
                 System.out.println(i+ " while循环" );
                 i++;
             }
         }
     }
}

   运行该程序会发现,while循环会一直运行直到变量i的值超出Integer.MAX_VALUE。所以说直接调用interrupt方法不能中断正在运行中的线程。

  但是如果配合isInterrupted()能够中断正在运行的线程,因为调用interrupt方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()判断中断标志是否被置位来中断线程的执行。比如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  Test {
     
     public  static  void  main(String[] args)  throws  IOException  {
         Test test =  new  Test();
         MyThread thread = test. new  MyThread();
         thread.start();
         try  {
             Thread.currentThread().sleep( 2000 );
         catch  (InterruptedException e) {
             
         }
         thread.interrupt();
    
     
     class  MyThread  extends  Thread{
         @Override
         public  void  run() {
             int  i =  0 ;
             while (!isInterrupted() && i
                 System.out.println(i+ " while循环" );
                 i++;
             }
         }
     }
}

   运行会发现,打印若干个值之后,while循环就停止打印了。

  但是一般情况下不建议通过这种方式来中断线程,一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class  MyThread  extends  Thread{
         private  volatile  boolean  isStop =  false ;
         @Override
         public  void  run() {
             int  i =  0 ;
             while (!isStop){
                 i++;
             }
         }
         
         public  void  setStop( boolean  stop){
             this .isStop = stop;
         }
     }

   那么就可以在外面通过调用setStop方法来终止while循环。

注意:object.wait(),object.notifly()与lockSupport.park(),lockSupport.unpark()区别
1、针对维度,一个是对象,一个是线程。
 
 

你可能感兴趣的:([JAVA修炼之路三]-JAVA Thread 方法)