Java之多线程wait/notify机制

一、线程的生命周期

线程是一个动态执行的过程,也是一个从无到有再到死亡的过程。

1.new–新建状态
Thread thread = new Thread();
当创建一个Thread实例时,线程就被创建了,但是线程并没有启动(start)。
**2.runnable–就绪(可运行)状态(重点关注)
线程已经被启动,但是在等待操作系统分配CPU时间片;也就是说该线程就绪等待队列中等待操作系统分配资源。**

3.running – 运行状态
线程启动并获得了cpu时间片并执行其中的run方法,在执行过程中,除非线程主动放弃cpu资源或者优先级更高额线程进入,否则该线程一直执行到结束。

4.dead—死亡状态
线程执行结束或者被其他线程终止。
自然:run方法执行完毕;
突然:调用stop()方法让一个线程终止运行;

**5.blocked–阻塞状态—-(重点关注)
由于某种原因,导致正在执行的线程让出Cpu并暂停执行,即进入阻塞状态。
1)正在sleep 睡眠,是线程暂停执行,但是其所拥有的锁不会释放;一个睡眠着的线程在指定的时间过去可进入就绪状态。
2)正在wait等待,该线程所持有的锁自动释放,只有调用notify可以是该线程回到就绪状态。
3)正在suspend,被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)**

二、常用的多线程方法

1.run():线程的业务执行代码(线程进入运行所执行的代码)。
2.start():启动线程。
3.sleep():暂停线程,使其进入睡眠状态,继续拥有锁。
4.wait():线程自己调用,主动让出cpu并主动释放所拥有的锁,该线程也从运行态进入阻塞状态,只有等待其他线程唤醒它。
5.notify():线程自己调用,唤醒同一临界资源的其中随机的一个线程,使其从阻塞状态进入就绪(runnable)状态。当该线程执行完run,才会释放其所拥有的锁,并不是调用到notify就立马释放锁。
6.notifyAll():线程自己调用,唤醒同一临界资源的所有线程进入就绪状态。当该线程执行完run,才会释放锁。
7.join():线程自己调用,只有等待该线程执行完成,后面的业务代码才会执行。也就是说一直等待该线程执行结束,才会执行后续代码。

三、常用的多线程方法

1.临界资源:多个线程间共享的数据
1)互斥锁
–每一个对象实例都有一个可称为互斥锁的标记;
每一个对象实例都可以被多个线程访问使用,只是在需要的时候才会启动互斥锁标记机制,成为专用对象,达到同步互斥的效果。
–关键字synchronized用来与对象的互斥锁联系。
–当某个对象(普通的对象实例,类的字节码元对象等等任你想象到的对象)用synchronized修饰时,表明该对象已启动“互斥锁”机制。在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。

四、什么是wait和notify 机制?

1.wait 即线程从运行态进入等待阻塞状态队列,后续代码不再执行;然后释放同一公共资源(对象锁);
(释放锁,进入阻塞队列;如果线程不被唤醒,则一直处于阻塞状态)

2.notify 即线程A从运行态随机唤醒争夺同一公共资源(S)的一个线程,使得该线程从阻塞队列进入可运行状态(只要获得cpu和锁即可运行);之后等自己线程A结束,释放该对象的锁S。

3.notifyAll 可以使得所有在阻塞队列中的等待同一竞争公共资源(S)的线程(All),从阻塞状态进入可运行状态。优先级最高的线程最先执行,但也有可能是随机执行,取决于JVM虚拟机实现。

——-转

我们来解释一下.
  “wait()允许我们将线程置入“睡眠”状态”,也就是说,wait也是让当前线程阻塞的,这一点和sleep或者suspend是相同的.那和sleep,suspend有什么区别呢?

  区别在于”(wait)同时又“积极”地等待条件发生改变”,这一点很关键,sleep和suspend无法做到.因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部运行完才有机会.在同步方法和同步块中,无论sleep()还是suspend()都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放.
  而wait却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其他同步方法!在其它情况下(sleep啊,suspend啊),这是不可能的.
  但是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程还是要把这个对象锁收回来的呀.wait什么?就是wait别人用完了还给我啊!
  好,那怎么把对象锁收回来呢?
  第一种方法,限定借出去的时间.在wait()中设置参数,比如wait(1000),以毫秒为单位,就表明我只借出去1秒中,一秒钟之后,我自动收回.
  第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我马上就收回来.哎,假如我设了1小时之后收回,别人只用了半小时就完了,那怎么办呢?靠!当然用完了就收回了,还管我设的是多长时间啊.

  那么别人怎么通知我呢?相信大家都可以想到了,notify(),这就是最后一句话”而且只有在一个notify()或notifyAll()发生变化的时候,线程才会被唤醒”的意思了.
  因此,我们可将一个wait()和notify()置入任何同步方法或同步块内部,无论在那个类里是否准备进行涉及线程的处理。而且实际上,我们也只能在同步方法或者同步块里面调用wait()和notify().

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值