多线程问题之多生产者/多消费者 ##
package producer_consumer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 生产者,消费者
* 多生产者,多消费者
* 1·if判断标记,只有一次,会导致不该运行的线程运行了,出现数据错误的情况
* 2·while判断标记解决了线程获取执行权后是否要运行
* 3·notify只能唤醒一个线程,如果唤醒了本方线程没有意义,而且notify+while会导致死锁
* 4·notifyAll解决了本方线程有可能会唤醒本方另一线程并执行的问题
* (唤醒全部线程,本方线程经过判断会进入等待状态,只有对方线程会继续执行)
* */
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//创建一个锁对象
Lock lock = new ReentrantLock();
//通过已有的锁获取该锁上的监视器对象
//Condition con = lock.newCondition();
//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者
Condition producer_con = lock.newCondition();
Condition consumer_con = lock.newCondition();
//以下为使用synchronized实现锁功能
/*public synchronized void set(String name)
{
//if(flag)第一个版本,会出现代码末尾描述的问题一
while(flag)//将if改为while是需要某线程在被唤醒后再次判断flag,适用于以下的lock
try
{
this.wait();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);
flag = true;
//notify();有可能唤醒本方线程并执行,适用于以下的lock中的signal()
notifyAll();
}*/
//优化版
public void set(String name)
{
lock.lock();
try
{
while(flag)//用while比较安全,每次被唤醒都判断一次,以防数据出错
try
{
producer_con.await();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产..5.0."+this.name);
flag = true;
Thread.sleep(10);
consumer_con.signal();
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
/*public synchronized void out()
{
while(!flag)
try
{
this.wait();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费........."+this.name);
flag = false;
//notify();有可能唤醒本方线程并执行
notifyAll();
}*/
public void out()
{
lock.lock();
try
{
while(!flag)
try
{
consumer_con.await();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费........5.0........"+this.name);
flag = false;
Thread.sleep(10);
producer_con.signal();
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
@Override
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}
class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
@Override
public void run()
{
while(true)
{
r.out();
}
}
}
public class ProducerConsumer
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
/*
* 多生产者消费者问题一
* 1·产生原因:在某个时刻只有t0处于唤醒状态,当该线程执行到notify()时,恰好被唤醒的是
* 生产者t1线程,则当t2或t3被唤醒后输出的是跳过t0线程生产产品的结果如下:
* Thread-1...生产...烤鸭45228
* Thread-0...生产...烤鸭45229
* Thread-2消费.........烤鸭45229
* Thread-3消费.........烤鸭45229
* */