当前位置: 首页 > 后端技术 > Java

JAVA并发编程——线程等待唤醒机制与LockSupport

时间:2023-04-01 16:08:37 Java

1.线程等待唤醒机制概述2.Object类中的wait和notify方法实现线程等待和唤醒3.Condition接口中await之后的signal方法实现线程等待和唤醒4.Object和Condition使用的限制5.简介LockSupport类6.LockSupport类7中的Parkwait和unparkwakeup.总结1.线程等待唤醒机制概述通过前两篇博客:JAVA并发编程-Synchronized和Lock与Lock对JAVA并发编程的使用区别-生产者和消费者mode(traditionalversion&blockingqueueversion)我们对线程等待和唤醒机制有了初步的了解,写了几个demo申请一个线程唤醒另一个线程,但是这两种写法都不是很完善,以及具体不完善的地方,以及修改方案,在后面的博客中有说明。2、Object类中的wait和notify方法实现线程等待和唤醒publicclassLockDemo{publicstaticvoidmain(String[]args)//main方法,主线程的所有程序入口{ObjectobjectLock=newObject();//同一个锁,类似于资源类newThread(()->{synchronized(objectLock){try{objectLock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+"\t"+"被唤醒");},"t1").start();//暂停几秒钟Thread.sleep(3000);newThread(()->{synchronized(objectLock){objectLock.notify();}},"t2").start();缺陷:虽然上面的代码可以让一个线程唤醒另一个线程,但是它有这样一个缺陷:1)把notify放在wait方法前面,那么线程t1就不能被唤醒2)wait和notify方法必须是在一个同步块或方法中,并成对出现在3.Condition接口中使用await之后的signal方法实现线程等待和唤醒publicclassLockSupportDemo2{publicstaticvoidmain(String[]args){Locklock=newReentr蚂蚁锁();条件condition=lock.newCondition();newThread(()->{lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t"+"start");condition.await();System.out.println(Thread.currentThread().getName()+"\t"+"被唤醒");}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}},"t1").start();//暂停线程几秒try{TimeUnit.SECONDS.sleep(3L);}catch(InterruptedExceptione){e.printStackTrace();}newThread(()->{lock.lock();try{condition.signal();}catch(Exceptione){e.printStackTrace();}finally{lock.unlock();}System.out.println(Thread.currentThread().getName()+"\t"+"notified");},"t2").start();}}缺陷:1)await()方法必须是insign在al()方法之前2)Condition中的线程等待唤醒方法之前,需要获取锁4.Object和Condition的使用限制从上面可以看出1)线程必须先获取并持有锁,并且必须在锁块中(synchronizedorlock)2)必须等待然后唤醒,线程才能被唤醒Primitives。说到这里大家可能不太理解,下面继续看源码注释:基本意思是:LockSupport类使用了一个叫做Permit(权限)的概念来阻塞和唤醒线程。每个线程都有一个许可(permit),如果调用了park()方法,并且许可(permit为1),则线程会继续执行,否则线程会立即阻塞。permit只有1和0两个值,默认为0。权限可以看作是一个(0,1)信号量(Semaphore),但与Semaphore不同的是,权限的累计上限为1。6.LockSupport类中的parkwaiting和unparkwakeup先看文档中的park()和unpark()方法:park()/park(Objectblocker):阻塞当前线程/阻塞传入的特定线程unpark(Threadthread)唤醒处于阻塞状态的指定线程publicclassLockSupportDemo{publicstaticvoidmain(String[]args){//正常使用+无需锁块Threadt1=newThread(()->{System.out.println(Thread.currentThread().getName()+""+"1111111111111");LockSupport.park();System.out.println(Thread.currentThread().getName()+""+"2222222222222------end被唤醒");},"t1");t1.start();//暂停线程几秒try{TimeUnit.SECONDS.sleep(3);}catch(InterruptedExceptione){e.printStackTrace();}LockSupport.unpark(t1);System.out.println(Thread.currentThread().getName()+"-----LockSupport.unparrk()调用结束");}}优点:1)错误的先唤醒然后等待,LockSupport还是支持的2)没有无锁块要求缺点:1)因为标志位为1,线程只能被唤醒一次。连续的park()和unpark()没有效果。**7.总结今天我们主要学习了之前的线程等待唤醒机制--LockSupport的缺点和改进方法,LockSupport其实是为以后阅读aqs源码做的一个预知,它改进了之前的几个缺陷在唤醒机制中。

猜你喜欢