Java线程 生产者消费者问题

Java线程创建

  继承 Java.lang.Thread 类  劣势:无法继承其他类

  实现 Runnable接口    优势:可以让线程处理同一个资源 实现线程间的资源共享

Java线程状态

新建状态 

 使用new关键字和Thread类创建线程对象后 线程对象就处于新生状态    通过调用start()方法进入就绪状态

 不能对已经启动的线程再次调用start()方法 否则会出现 java.lang.IllegalThreadStateException异常

就绪状态

  线程位于可运行池中  cpu会在线程池中进行调度  一旦线程获取cpu 进入运行状态 就会自动调用run方法、

运行状态  

 如果线程在运行状态中失去了cpu资源,就会变为就绪状态

 如果线程调用sleep()方法  wait()方法  阻塞式的io方法 等会进入阻塞状态 

 run()方法执行完 stop  

出现error或者exception  退出 

阻塞状态

 线程让出cpu并且暂停自己的运行,进入阻塞状态

 在阻塞状态的线程不能进入就绪队列,只有当阻塞状态解除时才会重新进入就绪状态

死亡状态

  线程中的run方法执行完毕 或者强制性终止 就认为已经进入了死亡状态   死亡状态的线程不能执行 


生产者消费者问题

  生产者的主要作用是 生成一定量的数据放到缓冲区中

  消费者的主要作用是 在缓冲区中消耗这些数据  

  生产者不断的生产  消费者不断的消费

  问题关键:生产者不会在缓冲区满时加入数据    消费者不会在缓冲区空时消耗数据

  解决策略:生产者在缓冲区满时休眠  消费者在缓冲区空时休眠   利用线程间的通信解决问题

  线程成为对象monitor的三种方式

      通过执行该对象的同步实例方法

      通过执行一个同步的声明对象

      通过执行同步静态方法

   一个线程在同一时刻可以拥有一个对象monitor

 方法一  利用Object类中的 wait 和notify  notifyAll解决问题

     Object  public final void wait()    使拥有该对象的monitor的当前进程等待    直到另一个线程调用该对象的notify() notifyall() 方法重新获得monitor  并恢复执行

     Object  public final void notify()  唤醒一个 在该对象上等待的  一个进程  如果有多个 则任意

     Object  public final void notifyAll() 唤醒所有 在该对象上等待 的所有进程

  方法二  利用java.util.concurrent 下的await()  signal() 方法解决生产者消费者问题

                         java.util.concurrent.locks.ReentrantLock    

              Condition();  返回此锁使用的条件实例

             lock();获取锁  如果不是由另一个线程持有 则立即返回 计数保持为1  当前线程已持有锁  计数递增 立即返回   如果锁 由另一个线程持有  则当前线程休眠 知道锁被收回

              unlock();释放锁  如果当前线程持有锁  计数减少   如果计数为0则释放锁  如果当前线程不是锁的拥有者 抛出异常

             await();等待发出信号或者中断当前进程  当其他某个线程调用signal() signalall()  

  定义抽象接口

   public  interface  Storage extends Runnable(){

       public  void  produce(int n);   //生产 方法

       public  void  consume(int n);// 消费  方法

   }

  实现抽象接口类 方法一StorageOne

    package producerConsumer;


import java.util.LinkedList;

public class StorageOne implements Storage{
    

private final int MAX_SIZE=100;  //仓库大小

private LinkedList<Object> list=new LinkedList<Object>(); //仓库

public LinkedList<Object> getList() {
return list;
}


public void setList(LinkedList<Object> list) {
this.list = list;
}


public int getMAX_SIZE() {
return MAX_SIZE;
}


//生产num个产品
public void produce(int num){
//使用 synchronized 代码块    保证同一时刻只有一个线程执行该代码
synchronized (list){
if (list.size()+num > MAX_SIZE){
System.out.println("当前库存为  "+list.size()+" 无法生产 "+num+" 个商品");
try {
list.wait();
} catch (InterruptedException e) {  
e.printStackTrace();
}

}
for(int i=1;i<=num;++i){
list.add(new Object());
}
System.out.println("当前库存为 "+list.size()+" 已经生产 "+num+" 个商品");
list.notifyAll();
}
}

//消费num个商品 
public void consume(int num){
       synchronized(list) {
      if(list.size()<num)
      {
      System.out.println("当前库存为  "+list.size()+" 无法消费 "+num+" 个商品");
      try {
list.wait();
  } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
  }
      }
      for(int i=1;i<=num;++i){
      list.remove();
      }
      System.out.println("当前库存为  "+list.size()+" 已经消费 "+num+" 个商品");
      list.notifyAll();
       }
}
}

实现抽象接口类  方法二  StorageTwo

  package producerConsumer;
import java.util.LinkedList;  
import java.util.concurrent.locks.Condition;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  /**
   * synchronized缺陷   当一个线程执行该代码块时 如果时间过长    除非出现异常 或者执行完毕   其他线程也只能等待释放该资源      影响程序效率
   * lock  通过lock实现同步访问  可以让等待的进程相应中断 也可让线程知道是否获得锁   但必须用户手动释放锁 防止发生死锁
   * Condition依赖于Lock接口  在lock与unlock中   才可以使用
   * @author inewline
   *
   */


public class StorageTwo  implements Storage
{  
    private final int MAX_SIZE = 100;   //仓库大小
  
    private LinkedList<Object> list = new LinkedList<Object>();  //仓库
  
    private final Lock lock = new ReentrantLock();  //锁
  
    private final Condition full = lock.newCondition();      // 仓库满的条件变量  
  
    private final Condition empty = lock.newCondition();     // 仓库空的条件变量   
    
    public int getMAX_SIZE()  
    {  
        return MAX_SIZE;  
    }  
  
    public LinkedList<Object> getList()  
    {  
        return list;  
    }  
  
    public void setList(LinkedList<Object> list)  
    {  
        this.list = list;  
    }  
    
    // 生产num个产品  
    public void produce(int num)       
    {  
        lock.lock();      // 获得锁  
  
        // 如果仓库剩余容量不足  
        while (list.size() + num > MAX_SIZE)  
        {  
        System.out.println("当前库存为"+list.size()+"无法生产"+num+"个商品");
            try  
            {  
                // 由于条件不满足,生产阻塞  
                full.await();  
            }  
            catch (InterruptedException e)  
            {  
                e.printStackTrace();  
            }  
        }    
        // 生产条件满足情况下,生产num个产品  
        for (int i = 1; i <= num; ++i)  
        {  
            list.add(new Object());  
        }  
        System.out.println("已经生产了"+num+"当前库存为"+list.size()); 
  
        // 唤醒其他所有线程  
        full.signalAll();  
        empty.signalAll();  
  
        // 释放锁  
        lock.unlock();  
    }  
  
    // 消费num个产品  
    public void consume(int num)  
    {  
        // 获得锁  
        lock.lock();  
  
        // 如果仓库存储量不足  
        while (list.size() < num)  
        {  
            System.out.println("当前库存为"+list.size()+"无法消费"+num+"个商品");
            try  
            {  
                // 由于条件不满足,消费阻塞  
                empty.await();  
            }  
            catch (InterruptedException e)  
            {  
                e.printStackTrace();  
            }  
        }  
  
        // 消费条件满足情况下,消费num个产品  
        for (int i = 1; i <= num; ++i)  
        {  
            list.remove();  
        }  
   
        System.out.println("已经消费了"+num+"当前库存为"+list.size());
  
        // 唤醒其他所有线程  
        full.signalAll();  
        empty.signalAll();  
  
        // 释放锁  
        lock.unlock();  
    }  
  


}

  生产者线程

  sleep()方法  位于thread类下的 public staticvoid sleep(long millis){ } 当前正在执行的线程休眠 (暂停执行)的指定毫秒数  线程不失去任何对象monitors的所有权

   package producerConsumer;

public class Producer extends Thread  {
    private int num;
    private Storage storage;
    
    public Storage getstorage() {
return storage;
}
public void setstorage(Storage storage) {
this.storage = storage;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}

    public Producer(Storage storage){
    this.storage=storage;
    }
    public void produce(int num){
    storage.produce(num);
    }
    public void run(){
    while(true){
     try {
Producer.sleep(1000);   
} catch (InterruptedException e) {
e.printStackTrace();
}
     produce(num);
    }
    }
}

  消费者线程

package producerConsumer;
public class Consumer extends Thread   {
    private int num;
    private Storage storage;
    public Consumer(Storage storage){
    this.storage=storage;
    }
    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 void consume(int num){
    storage.consume(num);
    }
    public void run(){
    while(true){
     try {
Consumer.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
          consume(num);
    }  
    }
}

测试程序调用   mainTest

     Storage storage=new StorageOne();

      //Storage storage=new StorageTwo();
      Producer p1 = new Producer(storage);  
       Producer p2 = new Producer(storage);  
       Producer p3 = new Producer(storage);  
       Producer p4 = new Producer(storage);  

       
       Consumer c1 = new Consumer(storage);  
       Consumer c2 = new Consumer(storage);  
       Consumer c3 = new Consumer(storage); 
       Consumer c4 = new Consumer(storage);
       
       p1.setNum(10);  
       p2.setNum(20);  
       p3.setNum(30);  
       p4.setNum(40);  
 
       
       c1.setNum(70);  
       c2.setNum(20);  
       c3.setNum(30);
       c4.setNum(40);
       
       c1.start();  
       c2.start();  
       c3.start(); 
       c4.start();
       
       p1.start();  
       p2.start();  
       p3.start();  
       p4.start();  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值