Java学习日志(12-1-多线程中锁的等待与唤醒)
2016-08-15 00:00
656 查看
多线程间通信
多个线程操作同一个资源,但是操作的动作不同
eg.同时输入输出会存在控制权转移导致输入一半就输出的问题
利用同步synchronized(唯一对象)解决控制权问题
将运行结果改为输入一条立即输出,依次循环——等待与唤醒
wait()等待 notify()唤醒 notifyAll唤醒全部
**因为是对持有锁的线程操作,因此只能用于同步之中,且必须标识锁——r.wait()
定义在Object类中是因为只有同一个锁上的wait线程,可以被同一个锁notify
锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
对代码进行优化
练习:消费者与生产者通信
Ver 1.0
Ver 2.0
存在多个消费者与生产者时
将if语句改为while,单次判断变为多次判断。同时改为notifyAll避免全部wait
总结
对于多个生产者和消费者,使用while进行判断,让被唤醒的线程再次判断flag
只用notify容易出现只唤醒本方线程的情况,导致所有线程都wait。
notifyAll能够唤醒对方线程。
Java 5.0以后将同步synchronized替换为Lock操作
将wait notify等操作替换为Condition对象
该对象可以对Lock锁进行操作
Input------->变量库------->Output
多个线程操作同一个资源,但是操作的动作不同
eg.同时输入输出会存在控制权转移导致输入一半就输出的问题
class Res{ String name; String sex; } class Input implements Runnable{ private Res r; Input(Res r){ this.r=r; } public void run(){ int x=0; while(true){ if(x==0){ r.name="Mike"; r.sex="female"; } else{ r.name="Lily"; r.sex="male"; } x=(x+1)%2; } } } class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ System.out.println(r.name+"___"+r.sex); } } } class InputOutputDemo{ public static void main(String[] args){ Res r=new Res(); Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); } }
利用同步synchronized(唯一对象)解决控制权问题
class Res{ String name; String sex; } class Input implements Runnable{ private Res r; Input(Res r){ this.r=r; } public void run(){ int x=0; while(true){ synchronized(r){ //共享数据 if(x==0){ r.name="Mike"; r.sex="female"; } else{ r.name="Lily"; r.sex="male"; } } x=(x+1)%2; } } } class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ synchronized(r){ //共享数据 System.out.println(r.name+"___"+r.sex); } } } }
将运行结果改为输入一条立即输出,依次循环——等待与唤醒
wait()等待 notify()唤醒 notifyAll唤醒全部
**因为是对持有锁的线程操作,因此只能用于同步之中,且必须标识锁——r.wait()
定义在Object类中是因为只有同一个锁上的wait线程,可以被同一个锁notify
锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
class Res{ String name; String sex; boolean flag=false; } class Input implements Runnable{ private Res r; Input(Res r){ this.r=r; } public void run(){ int x=0; while(true){ synchronized(r){ if(r.flag){ try{r.wait();}catch(Exception e){} } if(x==0){ r.name="Mike"; r.sex="female"; } else{ r.name="Lily"; r.sex="male"; } r.flag=true; r.notify(); } x=(x+1)%2; } } } class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ synchronized(r){ if(!r.flag){ try{r.wait();}catch(Exception e){} //必须抛出异常,且必须标识锁 } System.out.println(r.name+"___"+r.sex); r.flag=false; r.notify(); } } } }
对代码进行优化
class Res{ private String name; //权限私有化 private String sex; private boolean flag=false; public synchronized void set(String name,String sex){ //提供对外接口,注意同步数据 if(flag){ try{this.wait();}catch(Exception e){} } this.name=name; this.sex=sex; flag=true; this.notify(); } public synchronized void out(){ if(!flag){ try{this.wait();}catch(Exception e){} } System.out.println(name+"___"+sex); flag=false; this.notify(); } } class Input implements Runnable{ private Res r; Input(Res r){ this.r=r; } public void run(){ int x=0; while(true){ if(x==0){ r.set("Mike","Male"); } else{ r.set("Lily","Female"); } x=(x+1)%2; } } } class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ r.out(); } 3ff0 } } class InputOutputDemo{ public static void main(String[] args){ Res r=new Res(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); } }
练习:消费者与生产者通信
Ver 1.0
//存在问题:t1 t2唤醒后不再进行判断,可能生产出统一编号 class ProducerConsumerDemo{ public static void main(String[] args){ Resource r=new Resource(); Producer p=new Producer(r); Consumer c=new Consumer(r); Thread t1=new Thread(p); Thread t2=new Thread(p); Thread t3=new Thread(c); Thread t4=new Thread(c); t1.start(); t2.start(); t3.start(); t4.start(); } } class Resource{ private String name; private int count=1; private boolean flag=false; public synchronized void set(String name){ if(flag){ //第一次判断flag为false,不执行wait(),第二次为true,执行wait(). try{ this.wait(); } catch(Exception e){ } } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag=true; this.notify(); } public synchronized void out(){ if(!flag){ //第一次执行到这里的时候flag=true,不执行wait(). try{ this.wait(); } catch(Exception e){ } } System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name); flag=false; this.notify(); } } class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res=res; } public void run(){ while(true){ res.set("+goods+"); } } } class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res=res; } public void run(){ while(true){ res.out(); } } }
Ver 2.0
存在多个消费者与生产者时
将if语句改为while,单次判断变为多次判断。同时改为notifyAll避免全部wait
class Resource{ private String name; private int count=1; private boolean flag=false; public synchronized void set(String name){ while(flag){ try{ this.wait(); } catch(Exception e){ } } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag=true; this.notifyAll(); } public synchronized void out(){ while(!flag){ try{ this.wait(); } catch(Exception e){ } } System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name); flag=false; this.notifyAll(); } }
总结
对于多个生产者和消费者,使用while进行判断,让被唤醒的线程再次判断flag
只用notify容易出现只唤醒本方线程的情况,导致所有线程都wait。
notifyAll能够唤醒对方线程。
Java 5.0以后将同步synchronized替换为Lock操作
将wait notify等操作替换为Condition对象
该对象可以对Lock锁进行操作
import java.util.concurrent.locks.*; class Resource{ private String name; private int count=1; private boolean flag=false; private Lock lock=new ReentrantLock(); private Condition con_pro=lock.newCondition(); private Condition con_con=lock.newCondition(); public void set(String name)throws InterruptedException{ lock.lock(); try{ while(flag){ con_pro.await(); //只唤醒对方 } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag=true; con_con.signal(); } finally{ //释放锁的动作一定要执行 lock.unlock(); } } public void out()throws InterruptedException{ lock.lock(); try{ while(!flag){ con_con.await(); } System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name); flag=false; con_pro.signal(); } finally{ lock.unlock(); } } } class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res=res; } public void run(){ while(true){ try{ res.set("+goods+"); } catch(InterruptedException e){ } } } } class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res=res; } public void run(){ while(true){ try{ res.out(); } catch(InterruptedException e){ } } } }
相关文章推荐
- Java基础学习5_多线程(线程间通信--等待唤醒机制)
- Java学习日志(12-2-多线程相关操作)
- java多线程学习之线程通信-wait()等待 notify()唤醒
- java个人学习笔记18(多线程之间通信+等待唤醒机制)
- java基础12:线程间通信----等待唤醒机制
- java基本教程之java线程等待与java唤醒线程 java多线程教程
- Java多线程系列--“基础篇”05之 线程等待与唤醒
- java多线程中的生产者与消费者之等待唤醒机制@Version1.0
- java基本教程之java线程等待与java唤醒线程 java多线程教程
- Java基础12:线程;等待唤醒机制;锁;线程优先级;
- 黑马程序员 java基础 继承thread多线程学习日志
- Java基础 多线程 解决安全问题 等待唤醒机制 Lock Condition interrupt join setPriority yield
- 黑马程序员——java多线程之死锁和等待唤醒机制
- Java多线程系列--“基础篇”05之 线程等待与唤醒
- 黑马程序员——Java基础——多线程的同步、死锁和等待唤醒机制
- 黑马程序员java学习—多线程2:等待唤醒机制
- Java多线程系列--“基础篇”05之 线程等待与唤醒
- java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)
- java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)
- Java多线程(二)同步与等待唤醒