【Java高并发学习】不变模式与2种生产者-消费者模式

不变模式与2种生产者-消费者模式

概要图,可下载查看。

1.不变模式

一个对象一旦被创建,则它内部状态将永不发生改变,是线程安全的

  1. 当对象创建后,其内部状态和数据不再发生任何变化
  2. 对象需要共享,被多线程频繁访问
Java中实现不变模式:
  1. 去除setter方法以及所有修改自身属性的方法
  2. 将所有属性设置为final private,保证不可修改
  3. 类用final修饰,保证没有子类可以重载修改它的行为
  4. 需要提供一个完整的能创建对象的构造函数
/**
 * 不变模式下的对象类
 * @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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值