(五)Java线程之间的通信之wait notify 及Condition用法await Signal
1.因为涉及到对象锁,他们必须都放在synchronized中来使用. Wait、Notify一定要在synchronized里面进行使用。
2.Wait必须暂定当前正在执行的线程,并释放资源锁,让其他线程可以有机会运行
3. notify/notifyall: 唤醒因锁池中的线程,使之运行
wait notify
* wait notify一定要放在同步代码块中执行|同步方法中执行
* wait notify监视器对象必须为同一个对象
public class Demo31WaitAndNotify {
private volatile int signal;
public int getSignal() {
return signal;
}
public void setSignal(int signal) {
this.signal = signal;
}
public static void main(String[] args) {
Demo31WaitAndNotify d = new Demo31WaitAndNotify();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (d) {
System.out.println(Thread.currentThread().getName()+" "+"Thread 修改状态执行....");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" "+"Thread 修改状态成功!");
d.setSignal(1);
d.notify();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (d) {
//等待Signal信号为1开始执行,否则不能执行
while(d.getSignal()!=1){
try {
d.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//当信号为1时执行代码
System.out.println(Thread.currentThread().getName() + " " + "模拟代码执行....");
}
}
}).start();
}
}
Thread-0 Thread 修改状态执行....
Thread-0 Thread 修改状态成功!
Thread-1 模拟代码执行....
只有Thread-0执行完毕后进行notify之后,Thread-1才会执行。
经典范例eg:使用多线程循环打印abcabcabcabc...
public class Demo33ThreeMethodWaitAndNotify {
private int signal;
public synchronized void a(){
while(signal !=0 ){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"a...");
signal++;
notifyAll();
}
public synchronized void b(){
while(signal !=1 ){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"b...");
signal++;
notifyAll();
}
public synchronized void c(){
while(signal !=2 ){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"c...");
System.out.println("==========================================");
signal=0;
notifyAll();
}
public static void main(String[] args) {
Demo33ThreeMethodWaitAndNotify demo = new Demo33ThreeMethodWaitAndNotify();
A a = new A(demo);
B b = new B(demo);
C c = new C(demo);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
}
class A implements Runnable {
private Demo33ThreeMethodWaitAndNotify demo;
public A(Demo33ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.a();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
private Demo33ThreeMethodWaitAndNotify demo;
public B(Demo33ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.b();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class C implements Runnable {
private Demo33ThreeMethodWaitAndNotify demo;
public C(Demo33ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.c();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
wait与sleep区别
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu给其它线程,但是它的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备
获取对象锁进入运行状态。
Lock锁
在 jdk1.5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,Lock 接口提供了与 synchronized 关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。
Lock写法
Lock lock = new ReentrantLock(); lock.lock(); try{ //可能会出现线程安全的操作 }finally{ //一定在finally中释放锁 //也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常 lock.ublock(); }
|
Lock与synchronized 关键字的区别
Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。
Condition用法
Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
Condition condition = lock.newCondition();
res. condition.await(); 类似wait
res.Condition. Signal() 类似notify
/**
* 31Condition的使用及原理解析
* @author Administrator
* notify随机唤醒等待线程中的一个 condition(AQS)可以唤醒指定的线程。
* java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject
* -await
* -signal
* -signalAll
*
* print abcabcabcabc
*
*/
public class Demo34ThreeMethodWaitAndNotify {
private int signal=0;
Lock lock = new ReentrantLock();
Condition a = lock.newCondition();
Condition b = lock.newCondition();
Condition c = lock.newCondition();
public void a(){
lock.lock();
while(signal !=0 ){
try {
a.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"a...");
signal++;
b.signal();
lock.unlock();
}
public void b(){
lock.lock();
while(signal !=1 ){
try {
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"b...");
signal++;
c.signal();
lock.unlock();
}
public void c(){
lock.lock();
while(signal !=2 ){
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+"c...");
System.out.println("==========================================");
signal=0;
a.signal();
lock.unlock();
}
public static void main(String[] args) {
Demo34ThreeMethodWaitAndNotify demo = new Demo34ThreeMethodWaitAndNotify();
A a = new A(demo);
B b = new B(demo);
C c = new C(demo);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
}
class A implements Runnable {
private Demo34ThreeMethodWaitAndNotify demo;
public A(Demo34ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.a();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
private Demo34ThreeMethodWaitAndNotify demo;
public B(Demo34ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.b();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class C implements Runnable {
private Demo34ThreeMethodWaitAndNotify demo;
public C(Demo34ThreeMethodWaitAndNotify demo) {
this.demo = demo;
}
public void run() {
while(true){
demo.c();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}