java多线程解决同步问题的几种方式、原理和代码

来源:互联网 发布:海信网络机顶盒ip903h 编辑:程序博客网 时间:2024/05/18 01:01

在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。管道方法不建议使用,阻塞队列方法在问题4已有描述,现只提供前两种实现方法。

  • wait()/notify()方法
  • await()/signal()方法
  • BlockingQueue阻塞队列方法

  • PipedInputStream/PipedOutputStream

阻塞队列的一个简单实现:

public class BlockingQueue {  private List queue = new LinkedList();  private int  limit = 10;  public BlockingQueue(int limit){    this.limit = limit;  }  public synchronized void enqueue(Object item)throws InterruptedException  {    while(this.queue.size() == this.limit) {      wait();    }    if(this.queue.size() == 0) {      notifyAll();    }    this.queue.add(item);  }  public synchronized Object dequeue()  throws InterruptedException{    while(this.queue.size() == 0){      wait();    }    if(this.queue.size() == this.limit){      notifyAll();    }    return this.queue.remove(0);  }}
在enqueue和dequeue方法内部,只有队列的大小等于上限(limit)或者下限(0)时,才调用notifyAll方法。如果队列的大小既不等于上限,也不等于下限,任何线程调用enqueue或者dequeue方法时,都不会阻塞,都能够正常的往队列中添加或者移除元素。

  • wait()/notify()方法
  • 生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

    要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。


生产者类:

public class Producer extends Thread { // 每次生产的产品数量     private int num;     // 所在放置的仓库     private Storage storage;     // 构造函数,设置仓库     public Producer(Storage storage) {          this.storage = storage;     }     // 线程run函数     public void run() {          produce(num);     }     // 调用仓库Storage的生产函数     public void produce(int num) {          storage.produce(num);     }     public int getNum() {          return num;     }     public void setNum(int num) {          this.num = num;     }     public Storage getStorage() {          return storage;     }     public void setStorage(Storage storage) {          this.storage = storage;     }}

消费者类:

public class Consumer extends Thread { // 每次消费的产品数量     private int num;     // 所在放置的仓库     private Storage storage;     // 构造函数,设置仓库     public Consumer(Storage storage) {          this.storage = storage;     }     // 线程run函数     public void run() {          consume(num);     }     // 调用仓库Storage的生产函数     public void consume(int num) {          storage.consume(num);     }     // get/set方法     public int getNum() {          return num;     }     public void setNum(int num) {          this.num = num;     }     public Storage getStorage() {          return storage;     }     public void setStorage(Storage storage) {          this.storage = storage;     }}

仓库类:(wait()/notify()方法)

public class Storage { // 仓库最大存储量     private final int MAX_SIZE = 100;     // 仓库存储的载体     private LinkedList<Object> list = new LinkedList<Object>();     // 生产num个产品     public void produce(int num) {          // 同步代码段          synchronized (list) {               // 如果仓库剩余容量不足               while (list.size() + num > MAX_SIZE) {//相当于缓冲区满,生产者则等待                    System.out.print("【要生产的产品数量】:" + num);                    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");                    try {                         list.wait();// 由于条件不满足,生产阻塞                    } catch (InterruptedException e) {                         e.printStackTrace();                    }               }               // 生产条件满足情况下,生产num个产品               for (int i = 1; i <= num; ++i) {                    list.add(new Object());               }               System.out.print("【已经生产产品数】:" + num);               System.out.println(" 【现仓储量为】:" + list.size());               list.notifyAll();          }     }     // 消费num个产品     public void consume(int num) {          // 同步代码段          synchronized (list) {               // 如果仓库存储量不足               while (list.size() < num) {//相当于缓冲区空,消费者则等待                    System.out.print("【要消费的产品数量】:" + num);                    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");                    try {                         // 由于条件不满足,消费阻塞                         list.wait();                    } catch (InterruptedException e) {                         e.printStackTrace();                    }               }               // 消费条件满足情况下,消费num个产品               for (int i = 1; i <= num; ++i) {                    list.remove();               }               System.out.print("【已经消费产品数】:" + num);               System.out.println(" 【现仓储)量为】:" + list.size());               list.notifyAll();          }     }     // get/set方法     public LinkedList<Object> getList() {          return list;     }     public void setList(LinkedList<Object> list) {          this.list = list;     }     public int getMAX_SIZE() {          return MAX_SIZE;     }}


0 0
原创粉丝点击