Java笔记1 : 在生产者消费者模式中,线程通信与共享数据,死锁问题与解决办法
2013-12-26 18:39
891 查看
本例定义了4个类,这里说一下,方便下面讲解。分别是Product(产品),Producer(生产者),Consumer(消费者), Test(测试类)。
多线程之间通信与共享数据只要引用同一内存区域就可以了,做法就是new一个对象,传多个引用。
但是由于cpu的随机性,共享数据时容易出现非法数据,这个不必多说了。解决办法就是线程同步,在一个线程对共享的数据访问完之前,不允许另一个线程访问。
但是如果代码写成下面这样,则会出现死锁问题。(虽然本例使用的循环队列容量比较大,一般不会出现,不过这确实是安全隐患)
上面代码判断时用的while而不是if(同步代码中使用while代替if是一种技巧),这样避免判断完成之后cpu切换到另一线程,切换回来时由于没有再次判断,容易造成非法数据的问题。
解决死锁的第一种方案是使用synchronized和object中的各种方法,需要notifyAll代替notify,避免当队列已满且消费者全都wait时,生产者无法生产,造成死锁问题;第二种方案是使用Lock接口和Condition接口,可以用与第一种同样的方法,还可以利用Condition的多监视器绑定的特性,为生产者和消费者分别设置不同的监视器,这样保证生产者唤醒消费者,消费者唤醒生产者,就不会出现死锁问题了。
给出解决后的代码:
最后贴上Producer,Consumer,Test三个类的代码
多线程之间通信与共享数据只要引用同一内存区域就可以了,做法就是new一个对象,传多个引用。
Product pro = new Product(); Producer producer = new Producer(pro); Consumer consumer = new Consumer(pro);
但是由于cpu的随机性,共享数据时容易出现非法数据,这个不必多说了。解决办法就是线程同步,在一个线程对共享的数据访问完之前,不允许另一个线程访问。
但是如果代码写成下面这样,则会出现死锁问题。(虽然本例使用的循环队列容量比较大,一般不会出现,不过这确实是安全隐患)
public class Product { private boolean[] pro = new boolean[100]; private int head = 0; private int rear = 0; public synchronized void production() { while((rear + 1) % 100 == head) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产了一件产品, 放在位置 : " + rear); pro[rear] = true; rear = (rear + 1) % 100; this.notify(); } public synchronized void consume() { while(rear == head) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费了一件产品, 来自位置 : " + head); pro[head] = false; head = (head + 1) % 100; this.notify(); } }
上面代码判断时用的while而不是if(同步代码中使用while代替if是一种技巧),这样避免判断完成之后cpu切换到另一线程,切换回来时由于没有再次判断,容易造成非法数据的问题。
解决死锁的第一种方案是使用synchronized和object中的各种方法,需要notifyAll代替notify,避免当队列已满且消费者全都wait时,生产者无法生产,造成死锁问题;第二种方案是使用Lock接口和Condition接口,可以用与第一种同样的方法,还可以利用Condition的多监视器绑定的特性,为生产者和消费者分别设置不同的监视器,这样保证生产者唤醒消费者,消费者唤醒生产者,就不会出现死锁问题了。
给出解决后的代码:
public class Product { private boolean[] pro = new boolean[100]; private int head = 0; private int rear = 0; public synchronized void production() { while((rear + 1) % 100 == head) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产了一件产品, 放在位置 : " + rear); pro[rear] = true; rear = (rear + 1) % 100; this.notifyAll(); } public synchronized void consume() { while(rear == head) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费了一件产品, 来自位置 : " + head); pro[head] = false; head = (head + 1) % 100; this.notifyAll(); } }
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Product2 { private boolean[] pro = new boolean[100]; private int head = 0; private int rear = 0; Lock lock = new ReentrantLock(); Condition production_con = lock.newCondition(); Condition consume_con = lock.newCondition(); public void production() { lock.lock(); while((rear + 1) % 100 == head) { try { production_con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } try { System.out.println("生产了一件产品, 放在位置 : " + rear); pro[rear] = true; rear = (rear + 1) % 100; consume_con.signalAll(); } finally { lock.unlock(); } } public void consume() { lock.lock(); while(rear == head) { try { consume_con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } try { System.out.println("消费了一件产品, 来自位置 : " + head); pro[head] = false; head = (head + 1) % 100; production_con.signalAll(); } finally { lock.unlock(); } } }
最后贴上Producer,Consumer,Test三个类的代码
public class Producer implements Runnable { private Product pro; public Producer(Product pro) { this.pro = pro; } public void run() { for(int i = 0; i < 100; i++) { pro.production(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Consumer implements Runnable { private Product pro; public Consumer(Product pro) { this.pro = pro; } public void run() { for(int i = 0; i < 100; i++) { pro.consume(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Test { public static void main(String[] args) { //为了方便阅读,没有用匿名类 Product pro = new Product(); Producer producer = new Producer(pro); Consumer consumer = new Consumer(pro); Thread p1 = new Thread(producer); Thread p2 = new Thread(producer); Thread c1 = new Thread(consumer); Thread c2 = new Thread(consumer); p1.start(); p2.start(); c1.start(); c2.start(); } }
相关文章推荐
- java笔记:熟练掌握线程技术---基础篇之解决资源共享的问题(中)--前篇
- Android(java)学习笔记70:同步中的死锁问题以及线程通信问题
- Java 线程死锁的问题解决办法
- java项目——java中线程共享数据同步解决办法
- java笔记:熟练掌握线程技术---基础篇之解决资源共享的问题(中)--下篇
- java笔记:熟练掌握线程技术---基础篇之解决资源共享的问题(中)--中篇
- JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
- 多线程(线程间通信-多生产者多消费者问题-JDK1.5解决办法-范例),停止线程,线程中方法的区别,匿名内部类实现多线程,线程总结
- java 多线程(线程间通信-解决安全问题)
- pb11 -- PB12 查询数据时死锁问题解决办法<转>
- 关于java中long类型的数据转换json传到前台时丢失精度问题的解决办法
- 黑马程序员--读写字节数组,随机读写流,集合IO的思维导图,多线程部分,单例设计模式,线程和进程的概念,Java中的线程的创建方式,线程的随机性,线程的状态图,多线程操作共享数据的安全性,死锁
- Java线程同步锁解决共享数据安全
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
- 如何解决java线程中的资源共享的问题
- Java中tomcat memecached session 共享同步问题的解决办法
- java线程的同步安全问题三种解决办法
- Java与php共享Memcached存储数据中的问题与解决方法
- 29-多线程(线程间通信-多生产者多消费者问题-JDK1.5新特性-Condition).1 2 31-多线程(线程间通信-多生产者多消费者问题-JDK1.5解决办法-范例). 1 2
- JAVA学习笔记(1)_____模拟线程通信之生产者消费者问题