Java之多线程waitnotify机制

    xiaoxiao2021-11-06  63

    一、线程的生命周期

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

    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().

    转载请注明原文地址: https://ju.6miu.com/read-678060.html

    最新回复(0)