1).Android 价值千万 java线程专题:Wait¬ify&join&Yield
http://blog.csdn.net/whb20081815/article/details/65627387
2).Android 价值千万 java多线程同步 <二>Callable和Future&FutureTask
http://blog.csdn.net/whb20081815/article/details/65630694
3).Android 价值千万 java多线程<三>生产者消费者模型四种实现方法
http://blog.csdn.net/whb20081815/article/details/65635647
4).
Android 价值千万 java多线程同步 <四> synchronized&Lock&Atomic6种方式
http://blog.csdn.net/whb20081815/article/details/66971983
5).Android 价值千万java多线程同步 <五>CountDownLatch(计数器)和Semaphore(信号量)
http://blog.csdn.net/whb20081815/article/details/68498371
生产者消费者模型
同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。
(1)wait() / notify()方法
(2)BlockingQueue阻塞队列方法
(3)await() / signal()方法
(4)PipedInputStream / PipedOutputStream
先只介绍常用的2中
实际上,准确说应该是“生产者-消费者-仓储”模型,离开了仓储,生产者消费者模型就显得没有说服力了。
对于此模型,应该明确一下几点:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
一、wait() / notify()方法
wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。
wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。
notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
/**
* 仓库类Storage实现缓冲区
*
*
*/
public class StorageNotify
extends Strorage{
// 仓库最大存储量
private final int MAX_SIZE = 100;
// 仓库存储的载体
private LinkedList<Object> list = new LinkedList<Object>();
// 生产num个产品
public void produce(int num)
{
// 同步代码段
synchronized (list)
{
// 如果仓库剩余容量不足,如果list.size() + num>MAX_SIZE问题就来了
while (list.size() + num > MAX_SIZE)
{
System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:"
+ list.size() + "/t暂时不能执行生产任务!");
try
{
// 由于条件不满足,生产阻塞
list.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 生产条件满足情况下,生产num个产品
for (int i = 1; i <= num; ++i)
{
list.add(new Object());
}
System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size());
list.notifyAll();
}
}
// 消费num个产品
public void consume(int num)
{
// 同步代码段
synchronized (list)
{
// 如果仓库存储量不足
while (list.size() < num)
{
System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:"
+ list.size() + "/t暂时不能执行消费任务!");
try
{
// 由于条件不满足,消费阻塞
list.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 消费条件满足情况下,消费num个产品
for (int i = 1; i <= num; ++i)
{
list.remove();
}
System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size());
list.notifyAll();
}
}
public void testProduct(int type){
// 仓库对象
Strorage storage ;
if(type==BlockingQueueType){
storage = new StorageBlockingQueue();
}else{
storage = new StorageNotify();
}
// 生产者对象
Producer p1 = new Producer(storage);
Producer p2 = new Producer(storage);
Producer p3 = new Producer(storage);
Producer p4 = new Producer(storage);
Producer p5 = new Producer(storage);
Producer p6 = new Producer(storage);
Producer p7 = new Producer(storage);
// 消费者对象
Consumer c1 = new Consumer(storage);
Consumer c2 = new Consumer(storage);
Consumer c3 = new Consumer(storage);
// 设置生产者产品生产数量
p1.setNum(10);
p2.setNum(10);
p3.setNum(10);
p4.setNum(10);
p5.setNum(10);
p6.setNum(10);
p7.setNum(80);
// 设置消费者产品消费数量
c1.setNum(50);
c2.setNum(20);
c3.setNum(30);
// 线程开始执行
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
二、BlockingQueue阻塞队列方法
BlockingQueue是JDK5.0的新增内容,它是一个已经在内部实现了同步的队列,它可以在生成对象时指定容量大小。它用于阻塞操作的是put()和take()方法。
put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。
take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。
/**
* Created by Administrator on 2017/3/24.
* 采用阻塞队列的形式
*/
public class StorageBlockingQueue extends Strorage{
// 仓库最大存储量
private final int MAX_SIZE = 100;
// 仓库存储的载体
private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>(
100);
// 生产num个产品
public void produce(int num)
{
// 如果仓库剩余容量为0
if (list.size() == MAX_SIZE)
{
System.out.println("【库存量】:" + MAX_SIZE + "/t暂时不能执行生产任务!");
}
// 生产条件满足情况下,生产num个产品
for (int i = 1; i <= num; ++i)
{
try
{
// 放入产品,自动阻塞
list.put(new Object());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("【现仓储量为】:" + list.size());
}
}
// 消费num个产品
public void consume(int num)
{
// 如果仓库存储量不足
if (list.size() == 0)
{
System.out.println("【库存量】:0/t暂时不能执行消费任务!");
}
// 消费条件满足情况下,消费num个产品
for (int i = 1; i <= num; ++i)
{
try
{
// 消费产品,自动阻塞
list.take();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("【现仓储量为】:" + list.size());
}
结果:
【要消费的产品数量】:50/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11086/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:20/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11030/threadbase.peng.cx.com.threadproducecomsume D/Activity: performCreate Call secproduct feature valuefalse
03-24 18:57:18.509 11030-11088/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:10
03-24 18:57:18.509 11030-11030/threadbase.peng.cx.com.threadproducecomsume D/Activity: performCreate Call debug elastic valuetrue
03-24 18:57:18.509 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:30/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11089/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:20
03-24 18:57:18.509 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:20/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:30/t【库存量】:20/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11091/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:30
03-24 18:57:18.519 11030-11090/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:40
03-24 18:57:18.519 11030-11092/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:50
03-24 18:57:18.519 11030-11086/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:20/t【现仓储量为】:30
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:30/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:30/t【现仓储量为】:0
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11093/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:10
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11094/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:80/t【现仓储量为】:90
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:50/t【现仓储量为】:40
LinkedBlockingQueue:在代码里的用例之一:线程池 ExecutorService:
只要设置最大的值就可以了,其他自动处理
mThreadPool = Executors.newFixedThreadPool(3);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
AS源代码地址:不知道为什么上传不了