600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)

educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)

时间:2020-09-24 12:16:15

相关推荐

educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)

这篇文章主要从4个角度来讲多线程间的通信:

使用wait/notify实现线程间的通信生产者/消费者模式的实现方法join的使用ThreadLocal类的使用

等待/通知机制的实现:

(1)wait()方法属于Object类,作用是让当前执行代码的线程进行等待,该方法用来将当前线程置于"预执行队列"中,并且在wait()所在的代码行处停止执行,直到接到通知或者被中断为止。在调用wait()方法之前,线程必须获得该对象的对象级别锁,只能在同步方法或者同步块中调用wait()方法。在执行wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时没有持有适当的锁,就会抛出IllegalMonitorStateException异常,它是RuntimeException的一个子类。因此不需要进行异常捕获。

此处有个面试题,是关于为什么wait()方法必须在同步中?占小狼的公众号给出了答案,lost wake up问题,作者给出了生产和消费的模式距离来说明lost wake up问题,并给出要解决就必须同步,获取同一对象锁,连接如下:

阿里面试题,为什么wait()方法要放在同步块中?​mp.

(2)notify()方法也需要在同步方法或者同步代码块中调用,在调用前,线程必须获得该对象级别的锁,如果调用notify()时没有持有适当的锁,就会抛出IllegalMonitorStateException异常。该方法用来通知那些可能等待对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选其中一个呈wait状态的线程,对其发出notify,并使它等待获取该对象的对象锁。需要说明的是,在执行notify()方法后,当前线程不会马上释放锁,呈wait状态的线程也不会马上获得锁,必须等到notify()方法的线程执行完,走出同步代码块或则方法的时候,当前线程才会释放锁,wait状态的线程才可以获得锁。

notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使线程退出等待队列,进入可运行的状态,该方法一次只可以唤醒一个线程。

notifyAll()方法是可以唤醒所有正在等待队列中等待同一共享资源的全部线程,让其从等待状态退出,进入可运行状态,谁的优先级高,谁将会先被执行,也有可能随机执行,取决于JVM虚拟机的实现。

下面这段代码,因为没有“对象监视器”,没有同步锁的原因,所以出现了异常

package

异常:

Exception

下面这段代码,虽然使用了synchronized关键字,而且wait方法也在同步块中,但是因为当前线程main被挂起,一直处于等待,所以wait()方法后面的代码都没有执行机会。

package

运行结果:

sync

下面这段代码实现了线程间的通信,线程A先启动执行,然后调用wait方法,线程睡眠3秒,然后线程B启动执行,并执行了notify()方法,通知唤醒wait()的线程,当线程B执行完synchronized同步代码块,然后释放了对象锁,wait()的线程获取到了对象锁,然后继续执行。

package

运行结果:

begin

下面这段代码,是当list中添加元素5个的时候,然后就notify()另外一个wait()的线程。

package

运行结果:

wait

从运行结果可以看出,最开始是wait begin,结束是wait end。

线程的生命周期:

大致分为创建、可运行、运行、阻塞、销毁等五个状态。

其中可运行状态和运行状态可以相互转换,阻塞状态和可运行状态可以相互转换。

线程进入Runnable状态的情况:

(1)调用sleep()方法后经过的时间超过了指定的休眠时间

(2)线程调用的阻塞IO已经返回,阻塞方法执行完毕

(3)线程成功得获得了试图同步的监视器

(4)线程正在等待某个通知,其他线程发出了通知

(5)处于挂起状态的线程调用了resume方法恢复线程

线程出现阻塞状态的情况:

(1)线程调用sleep方法,主动放弃占用的处理器资源

(2)线程调用了阻塞式IO方法,在方法返回前,该线程被阻塞

(3)线程试图获得一个同步监视器,但是该同步监视器正被其他线程所持有

(4)线程等待某个通知

(5)程序调用了suspend()方法,挂起该线程,此方法容易导致死锁,应该避免调用。

wait方法执行后,锁会自动释放;notify()方法执行后,锁不会自动释放,除非执行完对应的synchronized方法,才会释放锁;sleep方法也是不释放锁的(????sleep方法不是指定线程休眠时间,休眠时间过后,线程就i 重新获得CPU,去执行吗????我的理解:多线程情况下,其中一个线程在同步块中被指定休眠时间,这个线程是在休眠期间不会释放锁,在休眠结束,同步块执行完以后就会释放对象锁)。

执行完同步代码块会释放对象锁;

在执行同步代码块的过程中,如果遇到异常导致线程终止,锁也会被释放;

在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒。

wait(long)方法:等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。

下面代码使用wait,分别有两个线程执行,都执行了同步方法,从控制台可以看出,程序依然没有执行完,正是因为A线程执行了wait()方法后,释放了对象锁,B线程才可以获取对象锁,然后执行同步代码块,执行wait。

package

运行结果:

begin

下面的程序中使用了wait和notify结合,其中wait执行完,其他线程还可以继续执行同步代码块,但是执行到notify的时候,程序就一直不能结束,原因是notify()方法指定完后没有释放对象锁,所以才导致这个问题发生,代码和运行结果如下所示:

package

begin

当interrupt()方法和wait()方法相遇,下面是示例代码和运行结果:

package

begin

下面这段代码是关于notify()方法,一次只可以唤醒一个线程(随机)的验证:

package

程序运行结果:

begin

多线程中的生产者和消费者模式:

(1)一个生产者和一个消费者:操作值

package

运行结果:set和get交替执行

set

(2)多生产者与多消费者:操作值:假死

下面的这段代码,因为存在使用notify(),可能生产唤醒生产者,消费者唤醒消费者,所以会造成假死状态。

package

运行结果:

productor

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。