多线程-生产者与消费者(存储数据与打印数据)

 

无线程同步:

存储数据:

 1 public class Storage {
 2     int data;
 3 
 4     public int getData() {
 5         return data;
 6     }
 7 
 8     public  void setData(int data) {
 9         this.data = data;
10     }
11 
12 }

 

产生数据:

 

 1 public class Counter implements Runnable {
 2     private Storage storage;
 3 
 4     public Counter(Storage storage) {
 5         this.storage = storage;
 6     }
 7 
 8     int count = 0;
 9 
10     @Override
11     public void run() {
12         while (true) {
13 
14             storage.setData(count);
15             System.out.println("Storage data set:" + count);
16 
17             try {
18                 Thread.sleep((int) (Math.random() * 1000));
19             } catch (InterruptedException e) {
20 
21                 e.printStackTrace();
22             }
23             count++;
24         }
25 
26     }
27 
28 }

 

读取数据:

 

 1 public class Printer extends Thread {
 2     private Storage storage;
 3 
 4     public Printer(Storage storage) {
 5         this.storage = storage;
 6     }
 7 
 8     public void run() {
 9         while (true) {
10 
11             System.out.println("Storage data print:" + storage.getData());
12 
13             try {
14                 Thread.sleep((int) (Math.random() * 1000));
15             } catch (InterruptedException e) {
16 
17                 e.printStackTrace();
18             }
19 
20         }
21 
22     }
23 
24 }

 

测试类:

 1 public class TestPrint {
 2 
 3     public static void main(String[] args) {
 4         Storage storage = new Storage();
 5 
 6         Counter counter = new Counter(storage);
 7         Thread th1 = new Thread(counter);
 8 
 9         Printer th2 = new Printer(storage);
10         th1.start();
11         th2.start();
12     }
13 
14 }

运行结果:

 

 分析运行结果可发现两个问题
1、生产者产生的资源可能没有被消费者获取
2、生产者产生的资源可能被消费者重复取得
 
造成这些问题的原因是两个线程在访问同一个对象时没有考虑同步的控制。
 
当消费者尚未取得资源时,生产者可能已经产生新的资源,使消费者错过一些资源
 
当生产者尚未产生新资源时,消费者再次执行get()方法,造成资源被重复获取
 
 
 
解决前述问题的关键是引入线程之间的同步控制逻辑 ,通过synchronized关键字锁定共享对象
 
方法名前加synchronized关键字标记
用synchronized(Object) {…}标记锁定的代码
当线程执行由synchronized关键字控制的代码时,就锁定了共享对象。其他线程如果需要操作该对象,就必须等待该线程执行完受保护的代码
 
 
修改后:
 
 1 public class Storage {
 2     int data;
 3     private boolean getable;
 4 
 5     public synchronized int getData() {
 6         while (getable == false) {
 7             try {
 8                 wait();
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12         }
13         getable = false;
14         notifyAll();
15         return data;
16     }
17 
18     public synchronized void setData(int data) {
19 
20         while (getable == true) {
21             try {
22                 wait();
23             } catch (InterruptedException e) {
24             }
25         }
26         this.data = data;
27         getable = true;
28         notifyAll();
29     }
30 
31 }

运行结果:

posted on 2014-08-19 17:34  @冰糖  阅读(371)  评论(0编辑  收藏  举报

导航