自己一直对Java多线程似是而非,刚好最近项目上线,时间相对比较空闲,重新温习了一遍多线程。参考书是<<疯狂java讲义>>。
以下自己动手写了一个生产者和消费者模式的代码。一共用了两种方法(synchronized 和 BlockingQueue)。Lock暂时没写。
一、synchronized 实现方法
1.先定义一个货物的实体Goods,用于生产者和消费者使用
package com.deshengzheng.thread.producer.notify;
public class Goods {
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
2.定义一个仓库Storge,用于存放和获取货物Goods
package com.deshengzheng.thread.producer.notify;
import java.util.LinkedList;
public class Storge {
private static final int MAX_VALUE = 10;
private LinkedList<Goods> list = new LinkedList<Goods>();
public void put() {
synchronized (list) {
try {
while (list.size() == MAX_VALUE) {
System.out.println(Thread.currentThread().getName() + ":仓库已满,请暂停生产");
list.wait();
}
Goods goods = new Goods();
goods.setId(String.valueOf(Math.random()));
goods.setName(Thread.currentThread().getName() + ":洗衣液");
if (list.add(goods)) {
System.out.println(Thread.currentThread().getName() + "添加了一个产品");
//在windows上添加这句代码,运行正常,但是在mac上添加这条代码,会出现
//必须等待生产者生产完之后,消费者才可以去取,一直没明白,Java不是跨平台吗?
//之后把这个睡眠添加在生产者线程的run方法里
//Thread.sleep((long) 300);
list.notifyAll();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void take() {
synchronized (list) {
try {
while(list.size() == 0) {
System.out.println(Thread.currentThread().getName() + ":仓库为空,请等待上架");
list.wait();
}
list.removeLast();
System.out.println(Thread.currentThread().getName() + "取了一个产品");
//在windows上添加这句代码,运行正常,但是在mac上添加这条代码,会出现
//必须等待生产者生产完之后,消费者才可以去取,一直没明白,Java不是跨平台吗?
//之后把这个睡眠添加在生产者线程的run方法里
//Thread.sleep( 300);
list.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3.有了仓库了,定义生产者来生产、消费者来消费
生产者
package com.deshengzheng.thread.producer.notify;
/**
* 生产者生产线程
* @ClassName:Producer
* @Description:
* @Author:zhengdesheng
* @Date:2017年7月10日下午5:03:51
* @version:1.0.0
*/
public class Producer extends Thread{
private Storge storge;
public Producer(String name,Storge storge){
super(name);
this.storge = storge;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
storge.put();
try {
Thread.sleep((long) 300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
消费者
package com.deshengzheng.thread.producer.notify;
/**
* 消费者消费线程
* @ClassName:Consumer
* @Description:
* @Author:zhengdesheng
* @Date:2017年7月10日下午5:04:38
* @version:1.0.0
*/
public class Consumer extends Thread{
private Storge storge;
public Consumer(String name,Storge storge){
super(name);
this.storge = storge;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
storge.take();
try {
Thread.sleep((long) 300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4.测试类
package com.deshengzheng.thread.producer.notify;
public class Test {
public static void main(String[] args) {
Storge storge = new Storge();
new Consumer("李晓明", storge).start();;
new Producer("富士康", storge).start();
Thread t1 = new Producer("长虹", storge);
// t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
Thread t = new Consumer("乔布斯", storge);
//t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
}
输出结果:
二、队列实现
队列实现区别只是在仓库类里面,所以这个地方只把仓库类贴出来,其他一模一样。
package com.deshengzheng.thread.producer.queue;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import com.deshengzheng.thread.producer.notify.Goods;
public class Storge {
private static final int MAX_VALUE = 10;
private BlockingQueue<Goods> list = new LinkedBlockingQueue<Goods>(MAX_VALUE);
public void put() {
Goods goods = new Goods();
goods.setId(String.valueOf(Math.random()*10));
goods.setName("洗衣液:"+goods.getId());
try {
list.put(goods);
System.out.println(Thread.currentThread().getName()+"添加了一个产品:"+goods.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void take() {
try {
Goods goods = list.take();
System.out.println(Thread.currentThread().getName()+"取出一个产品:"+goods.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印结果也是正确的。
两种方式都实现了消费者和生产者的功能。java本身的BlockingQueue实现非常不错了,一般选择这个就可以了。