JAVA线程通信

2018年6月19日12:11:31 发表评论 446

Object.wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。

使用Object.wait()方法和使用synchornized来分配​​ CPU​​ 时间是有本质区别:wait​​ 会释放锁,synchornized​​ 不释放锁。

Object.wait()Object.notify()​​ Object.notifyAll()只能在取得对象锁的时候才能调用。如果不加锁的话(也就是说必须在synchronized语句块中操作这三个方法,则会报​​ IllegalMonitorStateException​​ 异常。

调用Object.wait()实际上释放了Object的锁,否则其他线程也无法获得Object的锁,也就无法在synchronized(Object){​​ Object.notify() }​​ 代码段内唤醒等待锁的线程。

当调用Object.notify()或者Object.notifyAll()后,调用线程依旧持有Object锁,因此,等待线程(s)虽被唤醒,但是仍无法获得Object锁。直到调用线程退出synchronized块,释放Object锁后,等待线程(s)中的一个才有机会获得锁继续执行Object.wait()的下一条语句

一般在while()循环中使用Object.wait()方法而非if()语句

https://blog.csdn.net/chy555chy/article/details/52279544

重入锁

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程的得到了一个对象的锁后,再次请求此对象是可以再次得到该对象的锁。

  • 当一个线程请求一个由其他线程持有的锁时,发出请求的线程就会被阻塞,然而,由于内置锁是可重入的,因此如果某个线程试图获得一个已经由她自己持有的锁,那么这个请求就会成功,重入”​​ 意味着获取锁的操作的粒度是线程,而不是调用。

死锁

 

线程状态

线程状态从大的方面来说,可归结为:初始状态可运行状态不可运行状态消亡状态,具体可细分为7个状态,说明如下:

 

  • 线程的实现有两种方式,一是继承​​ Thread​​ 类,二是实现​​ Runnable​​ 接口,但不管怎样,当我们​​ new​​ ​​ Thread​​ 实例后,线程就进入了初始状态

  • 当该对象调用了​​ start()​​ 方法,就进入可运行状态

  • 进入可运行状态后,当该对象被操作系统选中,获得​​ CPU​​ 时间片就会进入运行状态

  • 进入运行状态后​​ case​​ 就比较多,大致有如下情形:

  • run()​​ 方法或​​ main()​​ 方法结束后,线程就进入终止状态

  • 当线程调用了自身的​​ sleep()​​ 方法或其它线程的​​ join()​​ 方法,就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源)。当​​ sleep()​​ 结束或​​ join()​​ 结束后,该线程进入可运行状态,继续等待OS分配时间片;

  • 当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被锁牢​​ (synchronized,lock)​​ ,将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入可运行状态,等待​​ OS​​ 分配​​ CPU​​ 时间片;

  • 当线程调用​​ wait()​​ 方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用​​ notify()​​ ​​ notifyAll()​​ 方法才能被唤醒(由于​​ notify()​​ 只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用​​ notifyAll()​​ 方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。

  • 当线程调用​​ stop​​ 方法,即可使线程进入消亡状态,但是由于​​ stop​​ 方法是不安全的,不鼓励使用,大家可以通过​​ run​​ 方法里的条件变通实现线程的​​ stop​​ 

线程通信

Object方法中有:

 

void notify()​​ 

Wakes up a single thread that is waiting on this object’s monitor.​​ 

译:唤醒在此对象监视器上等待的单个线程

The choice is arbitrary说明了是随意唤醒等待队列中的一个线程。

 

void notifyAll()​​ 

Wakes up all threads that are waiting on this object’s monitor.​​ 

译:唤醒在此对象监视器上等待的所有线程

 

void wait()​​ 

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.​​ 

译:导致当前的线程等待,直到其他线程调用此对象的notify()​​ 方法或​​ notifyAll()​​ 方法

 

void wait(long timeout)​​ 

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.​​ 

译:导致当前的线程等待,直到其他线程调用此对象的notify()​​ 方法或​​ notifyAll()​​ 方法,或者指定的时间过完。

 

void wait(long timeout, int nanos)​​ 

Causes the current thread to wait until another thread invokes the​​ notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.​​ 

译:导致当前的线程等待,直到其他线程调用此对象的notify()​​ 方法或​​ notifyAll()​​ 方法,或者其他线程打断了当前线程,或者指定的时间过完。

 

notify()​​ ​​ notifyAll()​​ 的区别

调用notifyAll()通知所有线程继续执行,只能有一个线程在执行其余的线程在等待(因为在所有线程被唤醒的时候在​​ synchornized块中)。这时的等待和调用notifyAll()前的等待是不一样的。

  • notifyAll前:在对象上休息区内休息。

  • notifyAll后:在排队等待获得对象锁。

notify()和​​ notifyAll()都是把某个对象上休息区内的线程唤醒, notify()只能唤醒一个,但究竟是哪一个不能确定,而​​ notifyAll()则唤醒这个对象上的休息室中所有的线程。 ​​​​ 

一般有为了安全性,我们在绝对多数时候应该使用notifiAll(),除非你明确知道只唤醒其中的一个线程,至于有些书上说“notify​​ 唤醒同一对象监视器中调用​​ wait​​ 的第一个线程是没有根据的,因为​​ SUN​​ 公司是这样说的“The choice is arbitrary and occurs at the discretion of the implementation.”​​ 说明了是随意唤醒等待队列中的一个线程

weinxin
微信公众号
分享IT信息技术、北海生活的网站。提供北海本地化的信息技术服务。
连线北海

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: