不变模式与2种生产者-消费者模式
概要图,可下载查看。
1.不变模式
一个对象一旦被创建,则它内部状态将永不发生改变,是线程安全的
- 当对象创建后,其内部状态和数据不再发生任何变化
- 对象需要共享,被多线程频繁访问
Java中实现不变模式:
- 去除setter方法以及所有修改自身属性的方法
- 将所有属性设置为final private,保证不可修改
- 类用final修饰,保证没有子类可以重载修改它的行为
- 需要提供一个完整的能创建对象的构造函数
/**
* 不变模式下的对象类
* @author wsz
* @date 2017年12月26日
*/
public final class PCData {
private final int data;//私用且不可变
public PCData(int data) {
super();
this.data = data;
}
public PCData(String data) {
super();
this.data = Integer.valueOf(data);
}
public int getData() {//只提供get方法
return data;
}
@Override
public String toString() {
return "PCData [data=" + data + "]";
}
}
2.不变模式下的生产者-消费者
2.1生产对象(数据)
/**
* 不变模式下的对象类
* @author wsz
* @date 2017年12月26日
*/
public final class PCData {
private final int data;//私用且不可变
public PCData(int data) {
super();
this.data = data;
}
public PCData(String data) {
super();
this.data = Integer.valueOf(data);
}
public int getData() {//只提供get方法
return data;
}
@Override
public String toString() {
return "PCData [data=" + data + "]";
}
}
2.2生产者
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 生产者
* @author wsz
* @date 2017年12月26日
*/
public class Producer implements Runnable{
private volatile boolean isRunning = true;//生产开关,满足可见性、有序性(禁止指令重排序),但无法保证(复合操作)原子性
private BlockingQueue<PCData> queue; //生产仓库,内存缓冲区;数据共享通道
private static AtomicInteger count = new AtomicInteger();//生产编号;原子操作
private static final int SLEEPTIME = 1000;
public Producer(BlockingQueue<PCData> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
PCData data = null;
Random r = new Random();
System.out.println("start Producer id="+Thread.currentThread().getId());
try {
while(isRunning) {
Thread.sleep(r.nextInt(SLEEPTIME));
data = new PCData(count.incrementAndGet());//当前值+1;不变模式,提供完整的构造函数;
System.out.println(data+" put in queue");
if(!queue.offer(data, 2, TimeUnit.SECONDS)) {//最多等待2s进行数据放入
System.out.println("failed put in queue :"+data);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
//停止生产
public void stop() {
isRunning = false;
}
}
2.3消费者
import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
/**
* 消费者
* @author wsz
* @date 2017年12月26日
*/
public class Consumer implements Runnable{
private BlockingQueue<PCData> queue;//数据仓库
private static final int SLEEPTIME = 1000;
public Consumer(BlockingQueue<PCData> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
System.out.println("start Consumer id="+Thread.currentThread().getId());
Random r = new Random();
try{
while(true) {
PCData data = queue.take();//Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
if(null != data) {
int re = data.getData()*data.getData();
System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(),data.getData(),re));
Thread.sleep(r.nextInt(SLEEPTIME));
}
}
}catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
2.4测试类
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 测试类
* @author wsz
* @date 2017年12月26日
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<PCData> queue = new LinkedBlockingQueue<PCData>(10);
//生产者
Producer p1 = new Producer(queue);
Producer p2 = new Producer(queue);
Producer p3 = new Producer(queue);
//消费者
Consumer s1 = new Consumer(queue);
Consumer s2 = new Consumer(queue);
Consumer s3 = new Consumer(queue);
//线程池并开启
ExecutorService service = Executors.newCachedThreadPool();
service.execute(p1);
service.execute(p2);
service.execute(p3);
service.execute(s1);
service.execute(s2);
service.execute(s3);
//休眠并停止生产
Thread.sleep(5000);
p1.stop();
p2.stop();
p3.stop();
Thread.sleep(2000);
service.shutdown();
}
}
3.无锁缓存框架Disruptor下的生产者-消费者
使用Disruptor框架需要使用到disruptor.jar包。可在
maven下载disruptor,本次使用的是3.3.2版本。
3.1生产对象(数据)
/**
* 生产对象
* @author wsz
* @date 2017年12月26日
*/
public class PCData {
private long value;
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
}
3.2生产对象工厂
import com.lmax.disruptor.EventFactory;
/**
* 工厂类,在Disruptor系统初始化时,构造所有缓冲区中的实例对象
* @author wsz
* @date 2017年12月26日
*/
public class PCDataFactory implements EventFactory<PCData>{
@Override
public PCData newInstance() {
return new PCData();
}
}
3.3生产者
import java.nio.ByteBuffer;
import com.lmax.disruptor.RingBuffer;
/**
* 生产者
* @author wsz
* @date 2017年12月26日
*/
public class Producer {
private final RingBuffer<PCData> ringBuffer;//缓冲区,数据仓库
public Producer(RingBuffer<PCData> ringBuffer) {
super();
this.ringBuffer = ringBuffer;
}
public void pushData(ByteBuffer bb) {//数据放入缓冲区仓库,参数为ByteBuffer对象,可以包装任何数据
//此处用来存储long数据。
long sequence = ringBuffer.next();//得到下一个可用的序列号,
try {
PCData event = ringBuffer.get(sequence);//根据序列号获取可用的数据对象
event.setValue(bb.getLong(0));
}finally {
ringBuffer.publish(sequence);//数据发布,发布后消费者才能看见
}
}
}
3.4消费者
import com.lmax.disruptor.WorkHandler;
/**
* 消费者
* @author wsz
* @date 2017年12月26日
*/
public class Consumer implements WorkHandler<PCData>{
//框架回调函数,自动读取数据
@Override
public void onEvent(PCData event) throws Exception {
System.out.println(Thread.currentThread().getId()+":Event:--"+event.getValue()*event.getValue());
}
}
3.4测试类
import java.nio.ByteBuffer;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
/**
* 测试类
* @author wsz
* @date 2017年12月26日
*/
public class Test {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws InterruptedException {
Executor executor = Executors.newCachedThreadPool();
PCDataFactory factory = new PCDataFactory();
int bufferSize = 1024;//设置缓冲区大小
Disruptor<PCData> disruptor = new Disruptor<PCData>(factory, bufferSize, executor, ProducerType.MULTI, new BlockingWaitStrategy());
disruptor.handleEventsWithWorkerPool( //设置3个消费者实例,系统会将每一个消费者实例映射到一个线程中
new Consumer(),
new Consumer(),
new Consumer()
);
disruptor.start();//启动并初始化disruptor系统
//生产者不断向缓冲区仓库存入数据
RingBuffer<PCData> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
ByteBuffer bb = ByteBuffer.allocate(8);
for(int i =0;true;i++) {
bb.putLong(0,i);
producer.pushData(bb);
Thread.sleep(500);
System.out.println("add data "+i);
}
}
}
4.总结
本文介绍了高并发中使用到的不变模式、两种生产者-消费者模式,其中一种使用Disruptor框架。大致内容可查看图片中总结的知识。
github地址:https://github.com/BeHappyWsz/chart5.git