需求情景 涉及问题 代码实现(共三个类和一个main方法的测试类)
两个线程一个生产者个一个消费者 需求情景 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用标记或加锁机制 wait() / nofity() 方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。 wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。 notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
代码实现(共三个类和一个main方法的测试类) /** * Created by yuandl on 2016-10-11./** * 资源 */public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { if (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + '生产者------------' + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + '消费者****' + number); flag = false; notify(); } }
/** * Created by yuandl on 2016-10-11. * /** * 生产者 */public class Producer implements Runnable { private Resource resource; public Producer(Resource resource) { this.resource = resource; } @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } resource.create(); } } }
/** * 消费者 */ public class Consumer implements Runnable { private Resource resource; public Consumer(Resource resource) { this.resource = resource; } @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } resource.destroy(); } } }
/** * Created by yuandl on 2016-10-11. */ public class ProducerConsumerTest { public static void main(String args[]) { Resource resource = new Resource(); new Thread(new Producer(resource)).start();//生产者线程 new Thread(new Consumer(resource)).start();//消费者线程 } }
Thread-0生产者------------1 Thread-1消费者****1 Thread-0生产者------------2 Thread-1消费者****2 Thread-0生产者------------3 Thread-1消费者****3 Thread-0生产者------------4 Thread-1消费者****4 Thread-0生产者------------5 Thread-1消费者****5 Thread-0生产者------------6 Thread-1消费者****6 Thread-0生产者------------7 Thread-1消费者****7 Thread-0生产者------------8 Thread-1消费者****8 Thread-0生产者------------9 Thread-1消费者****9 Thread-0生产者------------10 Thread-1消费者****10
以上打印结果可以看出没有任何问题 ———————————————————— 多个线程,多个生产者和多个消费者的问题 需求情景 涉及问题 再次测试代码 /** * Created by yuandl on 2016-10-11. */ public class ProducerConsumerTest { public static void main(String args[]) { Resource resource = new Resource(); new Thread(new Consumer(resource)).start();//生产者线程 new Thread(new Consumer(resource)).start();//生产者线程 new Thread(new Producer(resource)).start();//消费者线程 new Thread(new Producer(resource)).start();//消费者线程 } }
Thread-0生产者------------100 Thread-3消费者****100 Thread-0生产者------------101 Thread-3消费者****101 Thread-2消费者****101 Thread-1生产者------------102 Thread-3消费者****102 Thread-0生产者------------103 Thread-2消费者****103 Thread-1生产者------------104 Thread-3消费者****104 Thread-1生产者------------105 Thread-0生产者------------106 Thread-2消费者****106 Thread-1生产者------------107 Thread-3消费者****107 Thread-0生产者------------108 Thread-2消费者****108 Thread-0生产者------------109 Thread-2消费者****109 Thread-1生产者------------110 Thread-3消费者****110
101生产了一次,消费了两次 105生产了,而没有消费
当两个线程同时操作生产者生产或者消费者消费时,如果有生产者或者的两个线程都wait()时,再次notify(),由于其中一个线程已经改变了标记而另外一个线程再次往下直接执行的时候没有判断标记而导致的。 if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
代码改进(Resource中的if->while) /** * Created by yuandl on 2016-10-11./** * 资源 */public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + '生产者------------' + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + '消费者****' + number); flag = false; notify(); } }
运行结果 最后代码改进(Resource中的notify()->notifyAll()) /** * Created by yuandl on 2016-10-11./** * 资源 */public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + '生产者------------' + number); flag = true;//将资源标记为已经生产 notifyAll();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + '消费者****' + number); flag = false; notifyAll(); } }
Thread-0生产者------------412 Thread-2消费者****412 Thread-0生产者------------413 Thread-3消费者****413 Thread-1生产者------------414 Thread-2消费者****414 Thread-1生产者------------415 Thread-2消费者****415 Thread-0生产者------------416 Thread-3消费者****416 Thread-1生产者------------417 Thread-3消费者****417 Thread-0生产者------------418 Thread-2消费者****418 Thread-0生产者------------419 Thread-3消费者****419 Thread-1生产者------------420 Thread-2消费者****420
以上就大功告成了,没有任何问题 文章来源:http://blog.csdn.net/linglongxin24/article/details/52788774 在学习过程中如果有任何的问题,请来极乐网提问!
|