标签:
1 //15同步问题的分析案例以及解决思路 2 3 //两个客户到一个银行去存钱,每个客户一次存100,存3次。 4 //问题,该程序是否有安全问题,如果有,写出分析过程,并定于解决方案。 5 6 /* 7 发现运行结果: 8 sum=200 9 sum=200 10 sum=300 11 sum=400 12 sum=600 13 sum=500 14 15 打印错乱,不关心,但是发现数值错误,没有100. 16 运行了几次,发现有对的。 17 18 19 20 说明多线程的随机性造成了安全问题。 21 哪的问题? 22 1,既然是多线程的问题,必须问题发生在多线程中 23 2,任务代码中是否有共性数据呢?b对象中的sum. 24 3,是否有对sum进行多次运算呢?有! 25 26 加同步就行了。 27 */ 28 //描述银行, 29 class Bank 30 { 31 private int sum; 32 private Object obj = new Object(); 33 public void add(int num) 34 { 35 synchronized(obj) 36 { 37 sum = sum+num; 38 System.out.println("sum="+sum);//每存一次,看到银行金额变化。 39 } 40 } 41 } 42 43 class Consumer implements Runnable 44 { 45 private Bank b = new Bank(); 46 public void run() 47 { 48 for(int x=0;x<3;x++) 49 { 50 b.add(100);//一次存100,循环3次。 51 } 52 } 53 } 54 class ThreadTest 55 { 56 public static void main(String[] args) 57 { 58 Consumer c = new Consumer(); 59 Thread t1 = new Thread(c); 60 Thread t2 = new Thread(c); 61 t1.start(); 62 t2.start(); 63 } 64 }
1 //同步函数相关问题,以及同步函数和同步代码块的比较 2 /* 3 同步的另一种体现形式。同步函数。 4 5 同步函数使用的锁是哪个? 6 经过简单的分析:大概猜的是this。因为函数必须被对象调用。 7 8 验证: 9 写一个同步代码块,写一个同步函数。如果同步代码块中的锁对象和同步函数中的锁对象 10 是同一个,就同步了,就没有错误的数据了,如果不是同一个锁对象,就不同步,会出现错误数据, 11 12 让两个线程,一个线程在同步代码块中执行,一个线程待同步函数中执行。 13 14 总结:同步函数使用的锁是this. 15 16 同步函数和同步代码块的的区别? 17 1,同步函数使用的锁是固定的this。当线程任务只需要一个同步时,完全可以通过同步函数来体现。 18 2,同步代码块使用的是锁可以是任意对象。当线程任务需要多个同步时,必须通过所来区分。这时必须使用同步代码块。 19 同步代码块较为常用。 20 21 如果只用一个同步时,完全可以简化为 22 */ 23 24 class Ticket implements Runnable 25 { 26 //1,描述票的数量 27 private int tickets = 100; 28 29 //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码, 30 //需要定义在run方法中。 31 //记住,线程任务中通常都有循环结构。 32 //private Object obj = new Object(); 33 boolean flag = true; 34 public void run() 35 { 36 if(flag){ 37 while(true) 38 { 39 synchronized(this) 40 { 41 if(tickets > 0) 42 { 43 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} 44 System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称 45 } 46 } 47 } 48 } 49 50 else{ 51 while(true) 52 { 53 this.sale(); 54 } 55 } 56 } 57 58 public synchronized void sale()//同步函数。具备了同步性的函数,使用的锁对象就是this 59 { 60 if(tickets > 0) 61 { 62 //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。 63 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} 64 System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称 65 } 66 } 67 } 68 69 70 class ThreadDemo4 71 { 72 public void main(String[] args) 73 { 74 //1,创建Runnable接口的子类对象。 75 Ticket t = new Ticket(); 76 77 //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。 78 Thread t1 = new Thread(t); 79 Thread t2 = new Thread(t); 80 81 //3,开启四个线程 82 t1.start(); 83 84 try{Thread.sleep(10);}catch(InterruptedException e){} 85 //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。 86 t.flag = false; 87 88 t2.start(); 89 } 90 }
1 /* 2 静态同步函数使用的锁不是this.而是字节码文件对象。类名.class 3 */ 4 5 class Ticket implements Runnable 6 { 7 //1,描述票的数量 8 private static int tickets = 100; 9 10 //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码, 11 //需要定义在run方法中。 12 //记住,线程任务中通常都有循环结构。 13 //private Object obj = new Object(); 14 boolean flag = true; 15 public void run() 16 { 17 if(flag){ 18 while(true) 19 { 20 synchronized(Ticket.class) 21 { 22 if(tickets > 0) 23 { 24 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} 25 System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称 26 } 27 } 28 } 29 } 30 31 else{ 32 while(true) 33 { 34 this.sale(); 35 } 36 } 37 } 38 39 public static synchronized void sale()//加了静态后,已经知道静态函数里面没有了this. 40 { 41 if(tickets > 0) 42 { 43 //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。 44 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} 45 System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称 46 } 47 } 48 } 49 50 51 class ThreadDemo5 52 { 53 public static void main(String[] args) 54 { 55 //1,创建Runnable接口的子类对象。 56 Ticket t = new Ticket(); 57 58 //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。 59 Thread t1 = new Thread(t); 60 Thread t2 = new Thread(t); 61 62 //3,开启四个线程 63 t1.start(); 64 65 try{Thread.sleep(10);}catch(InterruptedException e){} 66 //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。 67 t.flag = false; 68 69 t2.start(); 70 } 71 }
1 //单例懒汉模式的并发访问相关问题 2 /* 3 单例懒汉模式的并发访问相关问题 4 */ 5 6 //饿汉式;多线程并发没问题。 7 class Single 8 { 9 private static final Single s = new Single(); 10 11 private Single(){} 12 13 public static Single getInstance() 14 { 15 return s; 16 } 17 } 18 19 //懒汉式: 20 class Single 21 { 22 private static Single s = null; 23 24 private Single(){} 25 /* 26 并发访问,会有安全隐患,所以加入同步机制解决安全问题。 27 但是,同步的出现却降低了效率。(提稿效率的办法就是减少判断锁的次数) 28 可以通过双重判断的方式,解决效率问题,减少判断的次数。 29 30 */ 31 public static /*synchronized*/ Single getInstance() 32 { 33 if(s==null)//只要有一个线程把对象创建完,其他线程就再也不会判断锁了。 34 { 35 synchronized(Single.class) 36 { 37 if(s==null) 38 // --->0 --->1 39 s = new Single(); 40 } 41 } 42 return s; 43 } 44 } 45 class Demo implements Runnable 46 { 47 public void run() 48 { 49 Single.getInstance(); 50 } 51 } 52 53 class ThreadDemo6 54 { 55 public static void main(String[] args) 56 { 57 System.out.println("Hello World!"); 58 } 59 }
1 //同步的另一个弊端。死锁 2 /* 3 同步的另一个弊端。 4 5 情况之一:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。 6 这时容易引发一种现象,死锁。 7 这种情况能避免就避免。 8 9 //Thread-0 10 synchronized(obj1) 11 { 12 --->thread-0 obj1 13 synchronized(obj2) 14 { 15 16 } 17 } 18 19 //Thread-1 20 synchronized(obj2) 21 { 22 thread-1 obj2 23 synchronized(obj1) 24 { 25 26 } 27 } 28 29 */ 30 31 class Ticket implements Runnable 32 { 33 //1,描述票的数量 34 private int tickets = 100; 35 36 //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码, 37 //需要定义在run方法中。 38 //记住,线程任务中通常都有循环结构。 39 private Object obj = new Object(); 40 boolean flag = true; 41 public void run() 42 { 43 if(flag){ 44 while(true) 45 { 46 synchronized(obj)//obj锁 47 { 48 sale();//this锁 49 } 50 } 51 } 52 53 else{ 54 while(true) 55 { 56 this.sale(); 57 } 58 } 59 } 60 61 public synchronized void sale()//this锁 62 { 63 synchronized(obj)//obj锁 64 { 65 if(tickets > 0) 66 { 67 //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。 68 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} 69 System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称 70 } 71 } 72 } 73 } 74 75 76 class ThreadDemo7 77 { 78 public static void main(String[] args) 79 { 80 //1,创建Runnable接口的子类对象。 81 Ticket t = new Ticket(); 82 83 //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。 84 Thread t1 = new Thread(t); 85 Thread t2 = new Thread(t); 86 87 //3,开启四个线程 88 t1.start(); 89 90 try{Thread.sleep(10);}catch(InterruptedException e){} 91 //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。 92 t.flag = false; 93 94 t2.start(); 95 } 96 } 97 98 //这个程序在运行过程中死锁了。 99 /* 100 Thread-0..sale..100 101 Thread-0..sale..99 102 Thread-0..sale..98 103 Thread-0..sale..97 104 Thread-0..sale..96 105 Thread-0..sale..95 106 */
1 //死锁示例--面试会用到 2 class Test implements Runnable 3 { 4 private boolean flag; 5 Test(boolean flag) 6 { 7 this.flag = flag; 8 } 9 public void run() 10 { 11 if(flag) 12 { 13 while(true) 14 { 15 synchronized(MyLock.LOCKA) 16 { 17 System.out.println(Thread.currentThread().getName()+"if......locka"); 18 synchronized(MyLock.LOCKB) 19 { 20 System.out.println(Thread.currentThread().getName()+"if......lockb"); 21 } 22 } 23 } 24 } 25 else 26 { 27 while(true) 28 { 29 synchronized(MyLock.LOCKB) 30 { 31 System.out.println(Thread.currentThread().getName()+"else......lockb"); 32 synchronized(MyLock.LOCKA) 33 { 34 System.out.println(Thread.currentThread().getName()+"else......locka"); 35 } 36 } 37 } 38 } 39 } 40 } 41 42 //单独定义一个用于存储锁对象类。 43 class MyLock 44 { 45 public static final Object LOCKA = new Object(); 46 public static final Object LOCKB = new Object(); 47 } 48 class DeadLockTest 49 { 50 public static void main(String[] args) 51 { 52 //创建了两个线程任务。 53 Test t1 = new Test(true); 54 Test t2 = new Test(false); 55 56 Thread t11 = new Thread(t1); 57 Thread t22 = new Thread(t2); 58 t11.start(); 59 t22.start(); 60 } 61 }
1 //多线程间的通信-生产者&消费者-问题发生。 2 /* 3 多线程中最为常见的应用案例, 4 生产者消费者问题。 5 生产和消费同时执行,需要多线程。 6 但是执行的任务却不相同,处理的资源是相同的。线程间的通信。 7 8 1,描述资源。 9 2,描述生产者,因为具备着自己的任务。 10 3,描述消费者,因为具备着自己的任务。 11 12 问题1: 13 数据错误,已经被生产很早期的商品,才被消费到。 14 出现线程安全问题,需要用同步来解决。 15 问题已解决:不会再消费到之前很早期的商品。 16 17 问题2: 18 发现了连续生产却没有消费,同时对同一个商品进行多次消费。 19 希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。 20 21 搞清楚机个问题: 22 生产者什么时候应该生产呢? 23 当盘子中没有面包,就生产,如果有了面包,就不要消费。 24 25 消费者什么时候应该消费呢? 26 当盘子中已有面包,就消费,如果没有面包,就不要消费。 27 28 */ 29 30 //1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品 31 class Resource 32 { 33 private String name; 34 private int count=1; 35 36 //1,提供设置的方法。 37 public synchronized void set(String name) 38 { 39 //1,给成员变量赋值并加上编号。 40 this.name = name+count; 41 count++; 42 43 //2,打印生产了哪个商品。 44 System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name); 45 46 } 47 48 public synchronized void out() 49 { 50 System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name); 51 } 52 } 53 54 //2,描述生产者。 55 class Producer implements Runnable 56 { 57 private Resource r ; 58 //生产者一初始化就要有资源。需要将资源传递到构造函数中。 59 Producer(Resource r) 60 { 61 this.r = r; 62 } 63 public void run() 64 { 65 while(true) 66 { 67 r.set("面包"); 68 } 69 } 70 } 71 72 //3,描述消费者。 73 class Consumer implements Runnable 74 { 75 private Resource r ; 76 //消费者一初始化就要有资源。需要将资源传递到构造函数中。 77 Consumer(Resource r) 78 { 79 this.r = r; 80 } 81 public void run() 82 { 83 while(true) 84 { 85 r.out(); 86 } 87 } 88 } 89 90 class ThreadDemo8 91 { 92 public static void main(String[] args) 93 { 94 //创建资源对象。 95 Resource r = new Resource(); 96 97 //创建线程任务。 98 Producer pro = new Producer(r); 99 Consumer con = new Consumer(r); 100 101 //3,创建线程。 102 Thread t1 = new Thread(pro); 103 Thread t2 = new Thread(con); 104 105 t1.start(); 106 t2.start(); 107 } 108 }
1 //多线程间的通信-生产者&消费者-问题发生。以及等待唤醒机制。 2 /* 3 多线程中最为常见的应用案例, 4 生产者消费者问题。 5 生产和消费同时执行,需要多线程。 6 但是执行的任务却不相同,处理的资源是相同的。线程间的通信。 7 8 1,描述资源。 9 2,描述生产者,因为具备着自己的任务。 10 3,描述消费者,因为具备着自己的任务。 11 12 问题1: 13 数据错误,已经被生产很早期的商品,才被消费到。 14 出现线程安全问题,需要用同步来解决。 15 问题已解决:不会再消费到之前很早期的商品。 16 17 问题2: 18 发现了连续生产却没有消费,同时对同一个商品进行多次消费。 19 希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。 20 21 搞清楚机个问题: 22 生产者什么时候应该生产呢? 23 当盘子中没有面包,就生产,如果有了面包,就不要消费。 24 25 消费者什么时候应该消费呢? 26 当盘子中已有面包,就消费,如果没有面包,就不要消费。 27 28 生产者生产了商品后,应该去告诉消费者来消费。而这时的生产者应该处于等待状态。 29 消费者消费了商品后,应该告诉生产者去生产,而这时的消费者应该处于等待状态。 30 31 32 ====================================================== 33 等待/唤醒机制。 34 wait();会让线程处于等待状态,其实就是将线程临时存储到了线程池中。 35 notify();会唤醒线程池中任意一个等待的线程。 36 notifyAll();会唤醒线程池中所有的等待线程。 37 38 记住:这些方法必须使用在同步中,必须要标识wait,notify等方法所属的锁。 39 同一个锁上的notify,只能唤醒该锁上的wait线程。 40 41 为什么这些方法定义在了Object中呢? 42 因为这些方法必须标识所属的锁。而锁可以是任意对象,任意对象可以调用的方法必然是Objec的方法。 43 44 45 距离:小朋友抓人游戏。 46 */ 47 48 //1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品 49 class Resource 50 { 51 private String name; 52 private int count=1; 53 54 //定义标记。 55 private boolean flag = false; 56 57 //1,提供设置的方法。 58 public synchronized void set(String name) 59 { 60 if(flag) 61 try{this.wait();}catch(InterruptedException e){} 62 //1,给成员变量赋值并加上编号。 63 this.name = name+count; 64 count++; 65 66 //2,打印生产了哪个商品。 67 System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name); 68 69 //将标记该为true 70 flag = true; 71 //唤醒消费者。 72 this.notify(); 73 74 } 75 76 public synchronized void out() 77 { 78 if(!flag) 79 try{wait();}catch(InterruptedException e){} 80 System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name); 81 //将标记该为flase。 82 flag = false; 83 //唤醒生产者。 84 notify(); 85 } 86 } 87 88 //2,描述生产者。 89 class Producer implements Runnable 90 { 91 private Resource r ; 92 //生产者一初始化就要有资源。需要将资源传递到构造函数中。 93 Producer(Resource r) 94 { 95 this.r = r; 96 } 97 public void run() 98 { 99 while(true) 100 { 101 r.set("面包"); 102 } 103 } 104 } 105 106 //3,描述消费者。 107 class Consumer implements Runnable 108 { 109 private Resource r ; 110 //消费者一初始化就要有资源。需要将资源传递到构造函数中。 111 Consumer(Resource r) 112 { 113 this.r = r; 114 } 115 public void run() 116 { 117 while(true) 118 { 119 r.out(); 120 } 121 } 122 } 123 124 class ThreadDemo9 125 { 126 public static void main(String[] args) 127 { 128 //创建资源对象。 129 Resource r = new Resource(); 130 131 //创建线程任务。 132 Producer pro = new Producer(r); 133 Consumer con = new Consumer(r); 134 135 //3,创建线程。 136 Thread t1 = new Thread(pro); 137 Thread t2 = new Thread(con); 138 139 t1.start(); 140 t2.start(); 141 } 142 }
1 //多生产&多消费问题发生及解决。 2 /* 3 java.util.concurrent.locks 软件包中提供了相应的解决方案。 4 Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock(); 5 提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。 6 可以替代同步。 7 8 升级到JDK1.5,先别同步改为Lock. 9 */ 10 11 /* 12 多生产多消费。 13 问题1:生产了商品没有被消费,同一个商品被消费多次。 14 Thread-2....生产者...面包285 15 Thread-0....生产者...面包286 16 Thread-1....消费者...面包286 17 Thread-2....生产者...面包287 18 Thread-0....生产者...面包288 19 Thread-1....消费者...面包288 20 21 被唤醒的线程没有判断标记,造成了问题1的产生。 22 解决:只要让被唤醒的线程必须判断标记就可以了。将if判断标记的方式改为while判断标记。 23 注意:只要是多生产,多消费,必须是while判断标记。 24 25 问题2:while判断后,死锁了。 26 原因:生产方唤醒了线程池中的生产方的线程。本方唤醒了本方。 27 解决:希望本方要唤醒对方。没有对应方法,只能唤醒所有。 28 29 其实还是有一些问题的。效率低了。 30 */ 31 //1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品 32 class Resource 33 { 34 private String name; 35 private int count=1; 36 37 //定义一个锁对象。 38 private Lock lock = new ReentrantLock(); 39 40 //定义标记。 41 private boolean flag = false; 42 43 //1,提供设置的方法。 44 public synchronized void set(String name)// t1 t2 45 { 46 //if(flag) 47 while(flag) 48 try{this.wait();}catch(InterruptedException e){} 49 //1,给成员变量赋值并加上编号。 50 this.name = name+count;//商品1 51 count++;//2 52 //2,打印生产了哪个商品。 53 System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1 54 55 //将标记该为true 56 flag = true; 57 //唤醒消费者。 58 this.notifyAll(); 59 60 } 61 62 public synchronized void out()// t3 t4 63 { 64 //if(!flag) 65 while(!flag) 66 try{wait();}catch(InterruptedException e){} 67 System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name); 68 //将标记该为flase。 69 flag = false; 70 //唤醒生产者。 71 this.notifyAll(); 72 } 73 } 74 75 //2,描述生产者。 76 class Producer implements Runnable 77 { 78 private Resource r ; 79 //生产者一初始化就要有资源。需要将资源传递到构造函数中。 80 Producer(Resource r) 81 { 82 this.r = r; 83 } 84 public void run() 85 { 86 while(true) 87 { 88 r.set("面包"); 89 } 90 } 91 } 92 93 //3,描述消费者。 94 class Consumer implements Runnable 95 { 96 private Resource r ; 97 //消费者一初始化就要有资源。需要将资源传递到构造函数中。 98 Consumer(Resource r) 99 { 100 this.r = r; 101 } 102 public void run() 103 { 104 while(true) 105 { 106 r.out(); 107 } 108 } 109 } 110 111 class ThreadDemo10 112 { 113 public static void main(String[] args) 114 { 115 //创建资源对象。 116 Resource r = new Resource(); 117 118 //创建线程任务。 119 Producer pro = new Producer(r); 120 Consumer con = new Consumer(r); 121 122 //3,创建线程。 123 Thread t1 = new Thread(pro); 124 Thread t2 = new Thread(pro); 125 Thread t3 = new Thread(con); 126 Thread t4 = new Thread(con); 127 128 t1.start(); 129 t2.start(); 130 t3.start(); 131 t4.start(); 132 } 133 }
1 //多生产&多消费问题发生及解决。 2 import java.util.concurrent.locks.*; 3 /* 4 java.util.concurrent.locks 软件包中提供了相应的解决方案。 5 Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock(); 6 提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。 7 可以替代同步。 8 9 升级到JDK1.5,先别同步改为Lock. 10 已经将旧锁替换成新锁,那么所上的监视器方法(wait notify notifyAll )也应该替换 11 成新锁上的方法。 12 而JDK1.5中将这些原有的监视器方法封装到了一个Condition对象中。 13 想要获取监视器方法,需要先获取Condition对象。 14 15 Condition对象的出现其实就是替代了Object中的监视器方法。 16 await(); 17 signal(); 18 signalAll(); 19 将所有的监视器方法替换成了Condition. 20 功能和ThreadDemo10.java的程序一样,仅仅是用新的对象,改了写法而已。 21 但是问题依旧,效率还是很低。 22 老程序中可以通过两个嵌套完成,但是容易引发死锁。 23 24 新程序中,就可以解决这个问题。 25 可以在一个锁上加上多个监视器对象。 26 */ 27 class Resource 28 { 29 private String name; 30 private int count=1; 31 32 //定义一个锁对象。 33 private Lock lock = new ReentrantLock(); 34 //获取锁上的Condition对象。为了解决本方唤醒对方的问题,可以一个锁上创建两个监视器对象。 35 private Condition produce = lock.newCondition();//负责生产的. 36 private Condition consume = lock.newCondition();//负责消费的. 37 38 39 //定义标记。 40 private boolean flag = false; 41 42 //1,提供设置的方法。 43 public void set(String name)// t1 t2 44 { 45 //获取锁。 46 lock.lock(); 47 try{ 48 while(flag) 49 try{produce.await();}catch(InterruptedException e){} 50 this.name = name+count;//商品1 51 count++; 52 System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1 53 54 //将标记该为true 55 flag = true; 56 //执行消费者的唤醒。而且是唤醒一个消费者就行了。 57 consume.signal(); 58 } 59 finally{ 60 lock.unlock();//一定要执行。 61 } 62 } 63 64 public void out()// t3 t4 65 { 66 lock.lock(); 67 try{ 68 while(!flag) 69 try{consume.await();}catch(InterruptedException e){} 70 System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name); 71 //将标记该为flase。 72 flag = false; 73 produce.signal(); 74 } 75 finally{ 76 lock.unlock(); 77 } 78 } 79 } 80 81 //2,描述生产者。 82 class Producer implements Runnable 83 { 84 private Resource r ; 85 //生产者一初始化就要有资源。需要将资源传递到构造函数中。 86 Producer(Resource r) 87 { 88 this.r = r; 89 } 90 public void run() 91 { 92 while(true) 93 { 94 r.set("面包"); 95 } 96 } 97 } 98 99 //3,描述消费者。 100 class Consumer implements Runnable 101 { 102 private Resource r ; 103 //消费者一初始化就要有资源。需要将资源传递到构造函数中。 104 Consumer(Resource r) 105 { 106 this.r = r; 107 } 108 public void run() 109 { 110 while(true) 111 { 112 r.out(); 113 } 114 } 115 } 116 117 class ThreadDemo11 118 { 119 public static void main(String[] args) 120 { 121 //创建资源对象。 122 Resource r = new Resource(); 123 124 //创建线程任务。 125 Producer pro = new Producer(r); 126 Consumer con = new Consumer(r); 127 128 //3,创建线程。 129 Thread t1 = new Thread(pro); 130 Thread t2 = new Thread(pro); 131 Thread t3 = new Thread(con); 132 Thread t4 = new Thread(con); 133 134 t1.start(); 135 t2.start(); 136 t3.start(); 137 t4.start(); 138 } 139 }
1 //接口 Condition示例: 2 class BoundedBuffer { 3 final Lock lock = new ReentrantLock();//锁 4 final Condition notFull = lock.newCondition(); //生产。 5 final Condition notEmpty = lock.newCondition(); //消费。 6 7 final Object[] items = new Object[100];//存储商品的容器。 8 int putptr/*生产者使用的脚标*/, takeptr,/*消费者使用的角标*/ count;//计数器。 9 10 /*生产者使用的方法,往数组中存储商品。*/ 11 public void put(Object x) throws InterruptedException { 12 lock.lock(); 13 try { 14 while (count == items.length) //判断计数器是否已到数据长度。慢了。 15 notFull.await();//生产者等待。 16 17 items[putptr] = x; //安照角标将商品存储到数组中。 18 19 if (++putptr == items.length)//如果存储的角标到了数组的长度,就将角标归零。 20 putptr = 0; 21 ++count;//计数器自增。 22 notEmpty.signal();//唤醒一个消费者。 23 } finally { 24 lock.unlock(); 25 } 26 } 27 28 public Object take() throws InterruptedException { 29 lock.lock(); 30 try { 31 while (count == 0) //如果计数器为零,说明没有商品,消费者需要等待。 32 notEmpty.await(); 33 Object x = items[takeptr]; //从数组中通过消费者角标获取商品。 34 35 if (++takeptr == items.length) //如果消费者角标等于数组长度,将角标归零。 36 takeptr = 0; 37 --count;//计数器自增。 38 notFull.signal();//唤醒生产者。 39 return x; 40 } finally { 41 lock.unlock(); 42 } 43 } 44 }
标签:
原文地址:http://www.cnblogs.com/sun-/p/5401215.html