代码实现上述框图:
1 //等待唤醒机制 2 3 /* 4 wait(),notify(),notifyAll()必须用在同步中,因为同步中才有锁。 5 指明让持有那个锁的线程去等待或被唤醒,例如object.wait(),表明让持有object这把锁的线程等待。 6 7 wait():让线程进入等待状态,就是把线程放入了线程池。 8 notify():唤醒线程池中的任意一个线程(持有特定锁的任意一个线程)。 9 notifyAll():唤醒所有线程。 10 11 wait(),notify(),notifyAll()为什么定义在Object中? 12 锁可以是任意的对象,任意对象都可以调用的方法需要定义在Object中。 13 */ 14 15 16 //描述数据 17 class Resource 18 { 19 public String name; 20 public String gender; 21 public boolean flag; //添加标记,默认为false;标志位的用途:例如:Input存完一组数据可能继续持有CPU,存完后将flag置反,则Input无法继续存入数据。 22 public Resource(){} 23 } 24 25 //描述输入任务 26 class Input implements Runnable 27 { 28 private Resource res; 29 public Input(Resource res) 30 { 31 this.res = res; 32 } 33 public void run() 34 { 35 int i = 1; 36 while(true) 37 { 38 synchronized(res) //加同步锁① 39 { 40 if(res.flag) 41 { 42 //等待的线程会放弃锁,跟sleep不同,sleep的线程仍然拥有锁。 43 try{res.wait();}catch(InterruptedException e){e.printStackTrace();} //判断flag标志,先判断该不该存,如果为true,放弃CPU。 44 } 45 if(i==1) 46 { 47 res.name = "猪小明"; 48 res.gender = "男"; 49 } 50 else 51 { 52 res.name = "腿腿"; 53 res.gender = "女"; 54 } 55 i=(++i)%2; //0、1切换 56 res.flag = true; 57 res.notify(); //唤醒对方,允许空唤醒。 58 //try{res.wait();}catch(InterruptedException e){e.printStackTrace();} 59 } 60 } 61 } 62 } 63 64 //描述输出任务 65 class Output implements Runnable 66 { 67 private Resource res; 68 public Output(Resource res) 69 { 70 this.res = res; 71 } 72 public void run() 73 { 74 while(true) 75 { 76 synchronized(res) //加同步锁②,①处和此处为同一把锁! 77 { 78 if(!res.flag) 79 { 80 try{res.wait();}catch(InterruptedException e){e.printStackTrace();} //判断flag标志,先判断该不该存,如果为false,放弃CPU。 81 } 82 System.out.println(res.name + "....." + res.gender); 83 res.flag = false; 84 res.notify(); //唤醒对方 85 //try{res.wait();}catch(InterruptedException e){e.printStackTrace();} 86 } 87 } 88 } 89 } 90 91 class TestDengdai 92 { 93 public static void main(String[] args) 94 { 95 //创建资源 96 Resource res = new Resource(); 97 //创建输入任务 98 Input input = new Input(res); 99 //创建输出任务 100 Output output = new Output(res); 101 //创建输入线程 102 Thread t1 = new Thread(input); 103 //创建输出线程 104 Thread t2 = new Thread(output); 105 //启动线程 106 t1.start(); 107 t2.start(); 108 109 } 110 }
上述代码实现存入一个输出一个的运行效果: