博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程之六种状态
阅读量:4068 次
发布时间:2019-05-25

本文共 4303 字,大约阅读时间需要 14 分钟。

一、java线程的六种状态

其中,RUNNABLE状态包括 【运行中】 和 【就绪】;

BLOCKED(阻塞态)状态只有在【等待进入synchronized方法(块)】和 【其他Thread调用notify()或notifyAll(),但是还未获得锁】才会进入;

二、sleep() 、yield()、join()与 wait()/notify()的区别

sleep() 、yield()、join()是Thread的方法,只放弃cpu,但是不放弃锁

1、Thread.sleep(long millis),一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。作用:给其它线程执行机会的最佳方式。

2、Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的CPU时间片,但不释放锁资源,由运行状态变为就绪状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。该方法与sleep()类似,只是不能由用户指定暂停多长时间。

3、t.join()/t.join(long millis),当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程进入就绪状态。

wait()是Object的方法,放弃cpu,也放弃锁

4、obj.wait(),当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout) timeout时间到自动唤醒。

5、obj.notify()唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。

public class Test {     public static void main(String[] args) {         new Thread1().start();                  new Thread2().start();     }          public static class Thread1 extends Thread{    	     	    @Override    	    public void run() {    		       	    	    synchronized (Test.class){    	    	    	   System.out.println("Thread1 start");    	    	    	       	    	    	   try {                    /**                     * 1、wait()和notify()是Object锁的方法                     * 2、wait()会让出锁    	    	    		                         */					Test.class.wait();				} catch (InterruptedException e) {					e.printStackTrace();				}    	    	    	       	    	    	   System.out.println("Thread1 go on ");      	    	    } 	    	    }     }          public static class Thread2 extends Thread{    	  	    @Override 	    public void run() { 		    	    	    synchronized (Test.class){ 	    	    	   System.out.println("Thread2 start"); 	    	    	    	    	    	  /** 	                    * 1、notify()调用后,该线程会等待该同步块执行完毕才释放锁  	    	    		     	                    */ 	    	    	   Test.class.notifyAll(); 	    	    	    	    	    	   try { 	    	    		  /** 	    	 	            * 1、sleep()是Thread的方法 	    	 	            * 2、sleep()不让出锁,只让出cpu    	    	    		     	    	 	            */					Thread2.sleep(500);				} catch (InterruptedException e) {					e.printStackTrace();				} 	    	    	    	    	    	   System.out.println("Thread2 go on"); 	    	    } 	    }  }}

三、LockSupport中的park() 和 unpark()

总结一下,LockSupport比Object的wait/notify有两大优势:

①LockSupport不需要在同步代码块里 ,所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦;

而wait/notify必须在同步块或同步方法中才能调用。

②unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序,而wait必须先于notify。

1、为什么LockSupport不需要在同步代码块里而wait()需要?

线程A执行一段业务逻辑后调用wait阻塞住自己。主线程调用notify方法唤醒线程A,线程A然后打印自己执行的结果:

public class TestObjWait {    public static void main(String[] args)throws Exception {        final Object obj = new Object();        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                try {                    synchronized (obj){                        obj.wait();                    }                }catch (Exception e){                    e.printStackTrace();                }                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        Thread.sleep(1000);        synchronized (obj){            obj.notify();        }    }}

使用LockSupport实现:

public class TestObjWait {    public static void main(String[] args)throws Exception {            Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                LockSupport.park();                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成        Thread.sleep(1000);        LockSupport.unpark(A);    }}

2、为什么LockSupport不需要担心unpark函数和park调用顺序,而Object的wait/notify需要关心?

如果我们将上面代码的这一句去掉:

//睡眠一秒钟,保证线程A已经计算完成        Thread.sleep(1000);

那么,使用wait()和notify()的就会出题,可能A会永远被挂起,因为主线程的notify()先于wait()调用了;

但是LockSupport的代码还是正确的执行,因为
LockSupport和每个使用它的线程都与一个许可(permit)关联。permit相当于1,0的开关,默认是0;
调用unpark就将permit赋值1;
调用park时,会判断permit如果为1,就会将permit赋值0,并且立即返回,如果permit为0,会阻塞在这里,直到permit变为1

转载地址:http://yhaji.baihongyu.com/

你可能感兴趣的文章
2. Add Two Numbers
查看>>
17. Letter Combinations of a Phone Number (DFS, String)
查看>>
93. Restore IP Addresses (DFS, String)
查看>>
19. Remove Nth Node From End of List (双指针)
查看>>
49. Group Anagrams (String, Map)
查看>>
139. Word Break (DP)
查看>>
23. Merge k Sorted Lists (Divide and conquer, Linked List) 以及java匿名内部类
查看>>
Tensorflow入门资料
查看>>
剑指_用两个栈实现队列
查看>>
剑指_顺时针打印矩阵
查看>>
剑指_栈的压入弹出序列
查看>>
剑指_复杂链表的复制
查看>>
服务器普通用户(非管理员账户)在自己目录下安装TensorFlow
查看>>
星环后台研发实习面经
查看>>
大数相乘不能用自带大数类型
查看>>
字节跳动后端开发一面
查看>>
CentOS Tensorflow 基础环境配置
查看>>
centOS7安装FTP
查看>>
FTP的命令
查看>>
CentOS操作系统下安装yum的方法
查看>>