java 生产者消费者 例子_Java Lock应用示例-生产者与消费者

Java Lock的使用以及与synchronized的区别很多文章已经讲解的很清楚了,这里不再详细讲解,可以参考java Lock讲解.

总的来说Lock的功能比synchronized更强大,功能更多,但一般的线程同步业务synchronized已经能够满足,对于一些特殊的要求,比如要知道线程获取锁的结果,线程获取锁时没有获取到,要求等待一段时间后仍没获取到就不去获取了,去做别的事情或者等待锁的过程中能够响应中断等等。Lock接口中的newCondition()方法用于获取锁对象上绑定的实例,用于线程的等待与唤醒,可以获取多个实例,而不是像synchronized只有一个锁对象(此时锁对象既是锁对象也是实例),好处是线程可以使用不同的实例,进行有针对的等待与唤醒,Lock接口唯一的实现类是ReentrantLock,下面我使用这个类来实现经典的生产者与消费者。

package cn.yanggy.demo04;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

* User:cool coding

* Date:2018/1/10

* Time:12:44

* 篮子

* 生产者和消费者需要向蓝子申请锁

*/

public class Bucket {

/**

* 蓝子

*/

private List buckets;

/**

* 蓝子的容量

*/

private final int maxCount=20;

/**

* 蓝子上的锁

*/

private final Lock lock=new ReentrantLock();

/**

* 消费锁对象

*/

private final Condition fetchLock;

/**

* 放入锁对象

*/

private final Condition addLock;

public Bucket(){

buckets=new ArrayList<>();

fetchLock =lock.newCondition();

addLock =lock.newCondition();

}

/**

* 获得锁

* @return

*/

public Lock getLock() {

return lock;

}

/**

* 获得消费锁对象

* @return

*/

public Condition getFetchLock() {

return fetchLock;

}

/**

* 获得放入锁对象

* @return

*/

public Condition getAddLock() {

return addLock;

}

/**

* 蓝子当前大小

* @return

*/

public int size(){

return buckets.size();

}

/**

* 放入

* @param obj

*/

public boolean add(String obj){

if(buckets.size()<20) {

buckets.add(obj);

return true;

}

else return false;

}

/**

* 随机获取一个蓝子里的东西

* @return

*/

public String fetch(){

int size=buckets.size();

if(size==1){

String obj=buckets.get(0);

buckets.clear();

return obj;

}

else if(size>1) {

int index = new Random().nextInt(size);

String obj=buckets.get(index);

buckets.remove(index);

return obj;

}else return null;

}

}

package cn.yanggy.demo04;

import java.util.Random;

/**

* User:cool coding

* Date:2018/1/10

* Time:12:49

* 生产苹果类

*/

public class Produce {

/**

* 生产苹果,耗时[1,5]秒(多线程共用)

* @return

*/

public static String produce(){

try {

Thread.sleep(new Random().nextInt(5)*1000+1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "苹果";

}

}

package cn.yanggy.demo04;

import java.awt.*;

import java.util.Random;

/**

* User:cool coding

* Date:2018/1/10

* Time:12:53

* 消费者

*/

public class Consumer implements Runnable {

/**

* 篮子

*/

private Bucket bucket;

public Consumer(Bucket bucket){

this.bucket=bucket;

}

@Override

public void run() {

while (true){

//拿锁

bucket.getLock().lock();

String obj=bucket.fetch();

if(obj==null) {

System.out.println(Thread.currentThread().getName()+":篮子空了");

//通知生产者生产

bucket.getAddLock().signalAll();

//消费者等待

try {

bucket.getFetchLock().await();

}catch (InterruptedException e){

}finally {

bucket.getLock().unlock();

}

}

else{

System.out.println(Thread.currentThread().getName()+":消费了"+obj);

bucket.getLock().unlock();

//消费完后,随机休息[1,5]秒钟

try {

Thread.sleep(new Random().nextInt(5)*1000+1000);

}catch (InterruptedException e){

}

}

}

}

}

package cn.yanggy.demo04;

import java.util.concurrent.ThreadLocalRandom;

/**

* User:cool coding

* Date:2018/1/10

* Time:13:02

* 生产者

* 分两步:先生产,然后放入蓝子

*/

public class Producer implements Runnable {

/**

* 蓝子

*/

private final Bucket bucket;

/**

* 当前手上拿着的东西

*/

private ThreadLocal currentHold=new ThreadLocal<>();

/**

* 记录总共生产出来东西的数量

*/

private ThreadLocal count=new ThreadLocal<>();

public Producer(Bucket bucket){

this.bucket=bucket;

}

@Override

public void run() {

//初始化本地线程执有的变量,不能写在Construct中,否则无效

currentHold.set(null);

count.set(0);

while (true){

String obj=currentHold.get();

if(obj==null) {//如果生产者手上没有拿着东西,则生产,否则先要放入篮子中

obj = Produce.produce();

count.set(count.get()+1);

System.out.println(Thread.currentThread().getName() + ":生产了第[" +count.get()+"]个"+obj);

}

bucket.getLock().lock();

boolean result=bucket.add(Thread.currentThread().getName()+"生产的第["+count.get()+"]个"+obj);

if(result) {

currentHold.remove();

System.out.println(Thread.currentThread().getName() + ":放入了第[" +count.get()+"]个"+obj);

System.out.println("篮子大小为:"+bucket.size());

bucket.getLock().unlock();

}

else {

currentHold.set(obj);

System.out.println(Thread.currentThread().getName() + ":篮子满了");

bucket.getFetchLock().signalAll();//通知消费者去消费

try {

bucket.getAddLock().await();//停止生产

} catch (InterruptedException e) {

e.printStackTrace();

}finally {

bucket.getLock().unlock();

}

}

}

}

}

package cn.yanggy.demo04;

/**

* User:cool coding

* Date:2018/1/10

* Time:13:16

*总共产生10个消费者,5个生产者

*/

public class Main {

public static void main(String[] args){

Bucket bucket=new Bucket();//篮子

Consumer consumer=new Consumer(bucket);//消费者

Producer producer=new Producer(bucket);//生产者

for(int i=0;i<5;i++){

Thread thread=new Thread(producer,"P["+i+"]");

Thread thread2=new Thread(consumer,"C["+i+"]");

thread.start();

thread2.start();

}

//延迟2秒钟,以便后五个消费者可以消费到东西

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

for(int i=5;i<10;i++){

Thread thread=new Thread(consumer,"C["+i+"]");

thread.start();

}

}

}

运行结果:

C[0]:篮子空了

C[1]:篮子空了

C[2]:篮子空了

C[3]:篮子空了

C[4]:篮子空了

P[3]:生产了第[1]个苹果

P[3]:放入了第[1]个苹果

篮子大小为:1

C[5]:消费了P[3]生产的第[1]个苹果

C[6]:篮子空了

C[7]:篮子空了

C[8]:篮子空了

C[9]:篮子空了

C[5]:篮子空了

P[3]:生产了第[2]个苹果

P[2]:生产了第[1]个苹果

P[4]:生产了第[1]个苹果

P[3]:放入了第[2]个苹果

篮子大小为:1

P[2]:放入了第[1]个苹果

篮子大小为:2

P[4]:放入了第[1]个苹果

篮子大小为:3

P[0]:生产了第[1]个苹果

P[1]:生产了第[1]个苹果

P[0]:放入了第[1]个苹果

篮子大小为:4

P[1]:放入了第[1]个苹果

篮子大小为:5

P[4]:生产了第[2]个苹果

P[2]:生产了第[2]个苹果

P[4]:放入了第[2]个苹果

篮子大小为:6

P[2]:放入了第[2]个苹果

篮子大小为:7

P[3]:生产了第[3]个苹果

P[3]:放入了第[3]个苹果

篮子大小为:8

P[1]:生产了第[2]个苹果

P[1]:放入了第[2]个苹果

篮子大小为:9

P[0]:生产了第[2]个苹果

P[0]:放入了第[2]个苹果

篮子大小为:10

P[4]:生产了第[3]个苹果

P[4]:放入了第[3]个苹果

篮子大小为:11

P[3]:生产了第[4]个苹果

P[2]:生产了第[3]个苹果

P[3]:放入了第[4]个苹果

篮子大小为:12

P[2]:放入了第[3]个苹果

篮子大小为:13

P[1]:生产了第[3]个苹果

P[1]:放入了第[3]个苹果

篮子大小为:14

P[4]:生产了第[4]个苹果

P[4]:放入了第[4]个苹果

篮子大小为:15

P[0]:生产了第[3]个苹果

P[0]:放入了第[3]个苹果

篮子大小为:16

P[2]:生产了第[4]个苹果

P[2]:放入了第[4]个苹果

篮子大小为:17

P[3]:生产了第[5]个苹果

P[3]:放入了第[5]个苹果

篮子大小为:18

P[1]:生产了第[4]个苹果

P[2]:生产了第[5]个苹果

P[1]:放入了第[4]个苹果

篮子大小为:19

P[2]:放入了第[5]个苹果

篮子大小为:20

P[3]:生产了第[6]个苹果

P[4]:生产了第[5]个苹果

P[3]:篮子满了

P[4]:篮子满了

C[0]:消费了P[3]生产的第[3]个苹果

C[1]:消费了P[3]生产的第[2]个苹果

C[2]:消费了P[4]生产的第[4]个苹果

C[3]:消费了P[3]生产的第[4]个苹果

C[4]:消费了P[2]生产的第[1]个苹果

C[6]:消费了P[0]生产的第[2]个苹果

C[7]:消费了P[3]生产的第[5]个苹果

C[8]:消费了P[2]生产的第[5]个苹果

C[9]:消费了P[4]生产的第[3]个苹果

C[5]:消费了P[4]生产的第[2]个苹果

P[0]:生产了第[4]个苹果

P[0]:放入了第[4]个苹果

篮子大小为:11

P[2]:生产了第[6]个苹果

P[2]:放入了第[6]个苹果

篮子大小为:12

C[9]:消费了P[2]生产的第[2]个苹果

C[8]:消费了P[2]生产的第[4]个苹果

C[2]:消费了P[0]生产的第[4]个苹果

P[0]:生产了第[5]个苹果

P[0]:放入了第[5]个苹果

篮子大小为:10

C[4]:消费了P[2]生产的第[6]个苹果

C[9]:消费了P[0]生产的第[3]个苹果

C[0]:消费了P[4]生产的第[1]个苹果

P[0]:生产了第[6]个苹果

P[0]:放入了第[6]个苹果

篮子大小为:8

P[1]:生产了第[5]个苹果

P[1]:放入了第[5]个苹果

篮子大小为:9

C[6]:消费了P[1]生产的第[4]个苹果

C[0]:消费了P[0]生产的第[5]个苹果

C[9]:消费了P[0]生产的第[1]个苹果

P[2]:生产了第[7]个苹果

C[1]:消费了P[1]生产的第[2]个苹果

P[2]:放入了第[7]个苹果

篮子大小为:6

C[5]:消费了P[1]生产的第[5]个苹果

P[0]:生产了第[7]个苹果

P[0]:放入了第[7]个苹果

篮子大小为:6

......

......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值