Java高并发
Java并发程序基础
- 线程的状态:new, runnable, blocked, waiting, timed_waiting, terminated。
public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;}
- Thread.run()和Thread.start()的区别是run不会开启新线程,在当前线程中,执行run()中的代码。
- 新建线程:可以使用重载实现run()方法或者使用public Thread(Runnable runnable)来定义线程;
- 终止线程:不能直接使用stop(),因为在结束线程时,会直接终止线程,并会立即释放这个线程所持有的锁。而这些锁恰恰是用来维持对象的一致性。可以使用变量的方式实现:
public class DemoThread extends Thread {volatile boolean stop = false; //退出线程标记public void stopThread() {stop = true;}@Overridepublic void run() {while (true) {if (stop) {break; //退出线程}synchronized (this) {//执行逻辑}Thread.yield(); //谦让,线程退出CPU}}}
- 线程中断interrupt
线程中断并不是立即退出,而是给线程发送一个通知,告知目标线程,希望退出。至于目标线程接收到通知后如何处理,则完全由目标线程自行决定。API如下:
public void Thread.interrupt() //中断线程public bool Thread.isInterrupted() //判断是否中断public void Thread.interrupted() //判断是否被中断,并清楚当前中断状态
在循环体中添加中断判断并添加中断的处理,如果在循环体中出现类似wait和sleep的操作,则只能通过中断来识别。因为sleep和wait会抛出InterruptedException中断异常。InterruptedException不是运行时异常,程序必须捕获并处理它,当线程处于sleep、状态时,如果被中断,就会触发该异常。
public static native void sleep(long millis) throws InterruptedException;
public class InterruptAndStopThread {public static void main(String args[]) throws InterruptedException {Thread thread = new Thread() {@Overridepublic void run() {while (true) {if (Thread.currentThread().isInterrupted()) {break;}try {Thread.sleep(600);} catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt(); //再次执行中断,置上中断标记位。异常后会清除该标记,如果不添加处理,则在下一个循环时无法捕获该中断}System.out.println("Running!");Thread.yield();}}};thread.start();Thread.sleep(2000);thread.interrupt();//中断}}
- 等待wait和通知notify
为了支持多线程之间的协作,JDK在Object类中提供了wait和notify接口,任何对象都可以调用该方法。调用必须包含在对应的synchronizied语句中,无论是wait或者notify都需要首先获取目标对象的一个监视器。wait通过synchronizied获取监视器。调用wait后自动释放监视器;notify通过synchronizied获取监视器,完毕后释放监视器。
public final void wait() throws InterruptedExceptionpublic final native void notify();
public class SimpleWaitAndNotify {final static Object object = new Object();public static class Thread1 extends Thread {public void run() {synchronized (object) {System.out.println(System.currentTimeMillis() + ":thread1 start !");try {System.out.println(System.currentTimeMillis() + ":thread1 wait for object !");object.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(System.currentTimeMillis() + ":thread1 end!");}}}public static class Thread2 extends Thread {public void run() {synchronized (object) {System.out.println(System.currentTimeMillis() + ":thread2 start ! notify one thread");object.notify();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(System.currentTimeMillis() + ":thread2 end!");}}}public static void main(String args[]) {Thread thread1 = new Thread1();Thread thread2 = new Thread2();thread1.start();thread2.start();}}
得到的结果是:thread1 start ! -> thread1 wait for object ! -> thread2 start ! notify one thread -> thread2 end! -> thread1 end!
wait和sleep的区别是:wait会自动释放锁,而sleep不会。
- suspend和resume
JDK已经废弃的接口,suspend在导致线程暂停的同时,不会去释放任何锁资源。如果resume操作意外在suspend之前执行,那么被挂起的线程可能很难有机会继续执行。
- 等待线程结束join和谦让yield
join:线程需要等待依赖线程执行完毕。join的本质是让调用线程wait在当前线程对象实例上,线程执行完毕后,被等待的线程会在退出前notifyAll通知所有的等待线程继续执行。
yield:是个静态方法,一旦执行,会使当前线程让出CPU。
public final void join() throws InterruptedExceptionpublic final synchronized void join(long millis) throws InterruptedExceptionpublic static native void yield()
public class JoinMain {public volatile static int i = 0;public static class AddThread extends Thread {public void run() {System.out.println("add!");for (i = 0; i < 1000000; i++) ;try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String args[]) throws InterruptedException {AddThread at = new AddThread();at.start();at.join(); //主线程等待at线程执行完毕System.out.println(i);}}
- volatile
为了确保变量被修改后,应用程序范围的所有线程都能够“看到”这个改动,虚拟机就必须采用特殊的手段,保证变量的可见性特点。volatile对保证操作的原子性有非常大的帮助,但是不能代替锁,无法保证一些复核操作的原子性。
如果没有把握,可以直接用synchronizied。例如:
public class ThreadVolatile extends Thread {public static volatile int n = 0;public void run() {for (int i = 0; i < 10; i++)try {n = n + 1;sleep(3); // 为了使运行结果更随机,延迟3毫秒} catch (Exception e) {}}public static void main(String[] args) throws Exception {Thread threads[] = new Thread[100];for (int i = 0; i < threads.length; i++)// 建立100个线程threads[i] = new ThreadVolatile();for (int i = 0; i < threads.length; i++)// 运行刚才建立的100个线程threads[i].start();for (int i = 0; i < threads.length; i++)// 100个线程都执行完后继续threads[i].join();System.out.println("n=" + ThreadVolatile.n);}}
如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
n = n + 1;
n++;
如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:
public class ThreadVolatile2 extends Thread {public static volatile int n = 0;public static synchronized void inc() {n++;}public void run() {for (int i = 0; i < 10; i++)try {inc(); // n = n + 1 改成了 inc();sleep(3); // 为了使运行结果更随机,延迟3毫秒} catch (Exception e) {}}public static void main(String[] args) throws Exception {Thread threads[] = new Thread[100];for (int i = 0; i < threads.length; i++)// 建立100个线程threads[i] = new ThreadVolatile2();for (int i = 0; i < threads.length; i++)// 运行刚才建立的100个线程threads[i].start();for (int i = 0; i < threads.length; i++)// 100个线程都执行完后继续threads[i].join();System.out.println("n=" + ThreadVolatile2.n);}}
- 线程组
public class ThreadGroupName implements Runnable {@Overridepublic void run() {String groupAndName = Thread.currentThread().getThreadGroup().getName() + "-" + Thread.currentThread().getName();while (true) {System.out.println("I am " + groupAndName);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String args[]) {ThreadGroup tg = new ThreadGroup("PrintGroup");Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");t1.start();t2.start();System.out.println(tg.activeCount());Thread t3 = new Thread(tg, new ThreadGroupName(), "T3");t3.start();System.out.println(tg.activeCount());tg.list();}}
- 守护线程:setDaemon需要在start之前设置,否则抛异常。
- 线程优先级:setPriority
/*** The minimum priority that a thread can have.*/public final static int MIN_PRIORITY = 1;/*** The default priority that is assigned to a thread.*/public final static int NORM_PRIORITY = 5;/*** The maximum priority that a thread can have.*/public final static int MAX_PRIORITY = 10;
- 线程安全和synchronizied
用法:
(1)指定加锁对象:进入同步代码前要获得给定对象;
synchronizied(instance) {}
(2)直接作用于实例对象:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁;
注意:因为加锁于实例对象,所以创建线程时需要传入同一个对象。
public class DemoThread extends Thread {private static DemoThread demoThread = new DemoThread();private static int i = 0;private synchronized void increase() {i++;}@Overridepublic void run() {for (int j = 0; j < 1000; j++) {increase();}}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(demoThread);Thread t2 = new Thread(demoThread);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
(3)直接作用于静态方法:相当于当前类加锁,进入同步代码前要获得当前类的锁;
public class DemoThread extends Thread {private static int i = 0;private static synchronized void increase() {i++;}@Overridepublic void run() {for (int j = 0; j < 1000; j++) {increase();}}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(new DemoThread());Thread t2 = new Thread(new DemoThread());t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
- 并发下的ArrayList和HashMap
public class ArrayListMultiThread {static ArrayList<Integer> arrayList = new ArrayList<Integer>(10);public static class AddThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {arrayList.add(i);}}}public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread(new AddThread());Thread thread2 = new Thread(new AddThread());thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(arrayList.size());}}
出现的结果可能有:
- 正常;
- ArrayList在扩容时,内部一致性被破坏,由于没有锁对象,另一个线程访问到了不一致的内部状态,导致越界问题;
- 出现隐蔽错误,ArrayList的大小小于20000。
最简单的方式是:使用线程安全的Vector代替ArrayList。
public class HashMapMultiThread {static Map<String, String> map = new HashMap<String, String>();public static class AddThread implements Runnable {int start = 0;public AddThread(int start) {this.start = start;}@Overridepublic void run() {for (int i = start; i < 100000; i += 2) {map.put(Integer.toString(i), Integer.toBinaryString(i));}}}public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread(new HashMapMultiThread.AddThread(0));Thread thread2 = new Thread(new HashMapMultiThread.AddThread(1));thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(map.size());}}
结果可能是:
- 正常;
- 正常退出,小于10000,
- 程序永远不能结束,当两个线程正在遍历HashMap的内部数据,put方法类似于链表的遍历,由于多线程的冲突,导致链表结构遭到破坏,当链表成环时,就出现了死循坏。死循坏在JDK8中已经不存在,但是在多线程使用HashMap依然会导致内部数据不一致。
最简单的方式是:使用ConcurrentHashMap代替HashMap。
JDK并发包
- 重入锁ReentrantLock
重入锁可以完全那替代synchronized关键字。提供了支持中断响应的接口,ReentrantLock的几个重要方法整理:
- lock():获得锁,如果锁已经被占用,则等待;
- lockInterruptibly:获得锁,但优先响应中断;
- tryLock():尝试获得锁,如果成功则返回true,失败则返回false。不等待锁;
- tryLock(long time, TimeUnit unit):在给定的时间尝试获得锁;
- unlock():释放锁;
- ReentrantLock(bool fair):公平锁;
public class IntLock implements Runnable {public static ReentrantLock lock1 = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();int lock;public IntLock(int lock) {this.lock = lock;}@Overridepublic void run() {try {if (lock == 1) {lock1.lockInterruptibly();Thread.sleep(500);lock2.lockInterruptibly();} else {lock2.lockInterruptibly();Thread.sleep(500);lock1.lockInterruptibly();}} catch (InterruptedException e) {e.printStackTrace();} finally {if (lock1.isHeldByCurrentThread()) {lock1.unlock();}if (lock2.isHeldByCurrentThread()) {lock2.unlock();}System.out.println(Thread.currentThread().getId() + ":线程退出");}}public static void main(String args[]) throws InterruptedException {IntLock r1 = new IntLock(1);IntLock r2 = new IntLock(2);Thread thread1 = new Thread(r1);Thread thread2 = new Thread(r2);thread1.start();thread2.start();Thread.sleep(1000);thread2.interrupt();}
上述代码分析:t1和t2启动之后,t1先占用lock1,再占用lock2;t2先占用lock2,再占用lock1,容易导致t1和t2处于相互等待状态,导致死锁。最后t2调用中断,最后t1能顺利执行,t2中断退出释放资源。
public class TryLock implements Runnable {public static ReentrantLock lock1 = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();int lock;public TryLock(int lock) {this.lock = lock;}@Overridepublic void run() {if (lock == 1) {while (true) {if (lock1.tryLock()) {try {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (lock2.tryLock()) {try {System.out.println(Thread.currentThread().getId() + ":My Job done;");return;} finally {lock2.unlock();}}} finally {lock1.unlock();}}}} else {while (true) {if (lock2.tryLock()) {try {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (lock1.tryLock()) {try {System.out.println(Thread.currentThread().getId() + ":My Job done;");return;} finally {lock1.unlock();}}} finally {lock2.unlock();}}}}}public static void main(String args[]) {TryLock r1 = new TryLock(1);TryLock r2 = new TryLock(2);Thread thread1 = new Thread(r1);Thread thread2 = new Thread(r2);thread1.start();thread2.start();}
上述代码分析:使用tryLock,由于线程不会傻傻等待,而是不断尝试,只要执行时间足够长,线程总是会得到所需要的资源,从而正常执行。
- 重入锁的好搭档:Condition条件
- await:是当前的线程等待,同时释放当前锁,当其他线程使用signal或者signalAll方法时,线程会重新获得锁并继续执行,或者被线程中断时,也会跳出等待,和Object.wait()相似;
- awaitUninterruptibly:和await相似,但是不会在等待过程中响应中断;
- signal:用于唤醒一个等待中的线程,和Object.notify()类似;
- signalAll:唤醒所有等待中的线程;
public class ReenterLockCondition implements Runnable {public static ReentrantLock lock = new ReentrantLock();public static Condition condition = lock.newCondition();@Overridepublic void run() {try {lock.lock();condition.await();System.out.println("Thread is going on");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String args[]) throws InterruptedException {ReenterLockCondition reenterLockCondition = new ReenterLockCondition();Thread thread1 = new Thread(reenterLockCondition);thread1.start();Thread.sleep(2000);lock.lock();condition.signal();lock.unlock();}}
代码分析:await调用后,线程释放锁,等待sign释放锁后,线程获得锁并执行剩下的代码。
- 信号量Semaphore
信号量是对锁的扩展,无论是内部锁synchronized还是重入锁ReentrantLock,一次只允许一个线程访问一个资源,而信号量却可以指定多个线程,同时访问一个资源。
public Semaphore(int permits):public Semaphore(int permits):public void acquire(int permits):public void acquireUninterruptibly(int permits):public boolean tryAcquire():public boolean tryAcquire(long timeout, TimeUnit unit):public void release():
public class SemapDemo implements Runnable {final Semaphore semp = new Semaphore(5);@Overridepublic void run() {try {semp.acquire();Thread.sleep(2000);System.out.println(Thread.currentThread().getId() + ":done!");semp.release();} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String args[]) {ExecutorService executorService = Executors.newFixedThreadPool(20);final SemapDemo demo = new SemapDemo();for (int i = 0; i < 20; i++) {executorService.submit(demo);}}}
- ReadWriteLock读写锁
ReadWriteLock是JDK5中提供的读写分离锁,读写分离锁有效地减少了锁竞争,以提升系统的性能。
public class ReadWriteLockDemo {private static Lock lock = new ReentrantLock();private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();private static Lock readLock = reentrantReadWriteLock.readLock();private static Lock writeLock = reentrantReadWriteLock.writeLock();private int value;public Object handleRead(Lock lock) throws InterruptedException {try {lock.lock();Thread.sleep(1000);return value;} finally {lock.unlock();}}public void handleWrite(Lock lock, int index) throws InterruptedException {try {lock.lock();Thread.sleep(1000);value = index;} finally {lock.unlock();}}public static void main(String args[]) {final ReadWriteLockDemo demo = new ReadWriteLockDemo();Runnable readRunnable = new Runnable() {@Overridepublic void run() {try {demo.handleRead(readLock);} catch (InterruptedException e) {e.printStackTrace();}}};Runnable writeRunnable = new Runnable() {@Overridepublic void run() {try {demo.handleWrite(writeLock, new Random().nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}}};for (int i = 0; i < 18; i++) {new Thread(readRunnable).start();}for (int i = 18; i < 20; i++) {new Thread(writeRunnable).start();}}}
代码分析:读线程为并行执行,写线程为串行执行。读读不堵塞,读写和写写堵塞。
- 倒计时器:CountDownLatch
用来控制线程等待,它可以让某个线程等待直到倒计时结束,再开始执行。
public class CountDownLatchDemo implements Runnable {static final CountDownLatch end = new CountDownLatch(10); //构造等待的线程数static final CountDownLatchDemo demo = new CountDownLatchDemo();@Overridepublic void run() {try {Thread.sleep(new Random().nextInt(3) * 1000);System.out.println("check complete");end.countDown();} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String args[]) throws InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) {executorService.submit(demo);}//等待10个线程执行完毕,再继续执行end.await();System.out.println("Fire!");executorService.shutdown();}}
- 线程池
public static ExecutorService newFixedThreadPool(int nThreads):固定线程数的线程池public static ExecutorService newSingleThreadExecutor():单线程线程池public static ExecutorService newCachedThreadPool():根据实际情况调整线程数量的线程池public static ScheduledExecutorService newSingleThreadScheduledExecutor():单线程任务线程池public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):固定线程数的任务线程池
/*** Creates a new {@code ThreadPoolExecutor} with the given initial* parameters.** @param corePoolSize the number of threads to keep in the pool, even* if they are idle, unless {@code allowCoreThreadTimeOut} is set* @param maximumPoolSize the maximum number of threads to allow in the* pool* @param keepAliveTime when the number of threads is greater than* the core, this is the maximum time that excess idle threads* will wait for new tasks before terminating.* @param unit the time unit for the {@code keepAliveTime} argument* @param workQueue the queue to use for holding tasks before they are* executed. This queue will hold only the {@code Runnable}* tasks submitted by the {@code execute} method.* @param threadFactory the factory to use when the executor* creates a new thread* @param handler the handler to use when execution is blocked* because the thread bounds and queue capacities are reached* @throws IllegalArgumentException if one of the following holds:* {@code corePoolSize < 0}* {@code keepAliveTime < 0}* {@code maximumPoolSize <= 0}* {@code maximumPoolSize < corePoolSize}* @throws NullPointerException if {@code workQueue}* or {@code threadFactory} or {@code handler} is null*/public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
- corePoolSize:线程数;
- maximumPoolSize:最大线程数;
- keepAliveTime:当线程数量大于corePoolSize时,多余的空闲线程的存活时间。
- unit:keepAliveTime的单位时间;
- workQueue:任务列表,被提交但尚未被执行的任务;
- threadFactory:线程工厂,用于创建线程;
- handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。
根据任务队列的功能,ThreadPoolExecutor的构造函数中可以使用以下的几种BlockingQueue:
(1)直接提交队列:SynchronousQueue,需要设置很大的maximumPoolSize值;
(2)有界任务队列:ArrayBlockingQueue,线程数量为0~maximumPoolSize,当线程数量大于corePoolSize时,任务存放到任务队列,当总线程数大于maximumPoolSize时,则执行拒绝策略;
(3)无界任务队列:LinkedBlockingQueue,线程数量最大值为corePoolSize,maximumPoolSize没有实际意义,当总线程数大于corePoolSize时,被存储到任务队列中;
(4)优先任务队列:PriorityBlockingQueue,可以根据任务自身的优先级顺序先后执行。
- 线程异常信息的封装
public class TraceThreadPoolExecutor extends ThreadPoolExecutor {public TraceThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}public void execute(Runnable task) {super.execute(wrap(task, clientTrace(), Thread.currentThread().getName()));}private Runnable wrap(final Runnable task, final Exception clientTrace, String name) {return () -> {try {task.run();} catch (Exception e) {clientTrace.printStackTrace();throw e;}};}private Exception clientTrace() {return new Exception("Client stack trace");}public static void main(String[] args) {TraceThreadPoolExecutor traceThreadPoolExecutor = new TraceThreadPoolExecutor(0, Integer.MAX_VALUE, 0L, TimeUnit.SECONDS, new SynchronousQueue<>());for (int i = 0; i< 5; i++) {traceThreadPoolExecutor.execute(new DivTask(100, i));}}public static class DivTask implements Runnable {int a, b;public DivTask(int a, int b) {this.a = a;this.b = b;}@Overridepublic void run() {double re = a / b;System.out.println(re);}}}
- JDK并发容器
- ConcurrentHashMap:高效并发的HashMap;
- CopyOnWriteArrayList:和ArrayList是一族的,在读多写少的场合,List性能非常好,远远好于Vector;
- ConcurrentLinkedQueue:高效并发队列,使用链表实现,线程安全的LinkedList;
- BlockingQueue:堵塞队列,适合作为数据共享的通道;
- ConcurrentSkipListMap:跳表的实现,有序Map,使用跳表的数据结构进行快速查找。
锁优化
- 提高锁的性能
- 减小锁持有时间:减少某个锁的占用时间,以减少线程间互斥的功能,提高系统的吞吐量;
- 减小锁粒度:减小锁粒度是削弱多线程锁竞争的有效手段,ConcurrentHashMap添加一个新的表项,首先根据hashcode得到该表项应该存放到哪个段中,然后对该段加锁,并完成put操作。默认有16段。
- 读写分离锁来替换独占锁:通过读写锁ReadWriteLock提高系统性能。
- 锁分离:读写锁根据读写操作功能上的不同,进行有效的分离,使用类似的分离思想,从而对独占锁进行分离。例如LinkedBlockingQueue,take()和put()的获取和存储操作,由于是链表,两个操作分别作用于队列的前端和尾端。
- 锁粗化:将一连串连续地对同一个锁不断进行请求和释放的操作时,便会把所有的锁操作整合成对锁的一次请求,减少对锁的请求同步次数。
- 无锁CAS
并发模式与算法
1. 单例模式
public class StaticSingleton {private StaticSingleton() {System.out.println("StaticSingle is create");}private static class SingletonHolder {private static StaticSingleton instance = new StaticSingleton();}public static StaticSingleton getInstance() {return SingletonHolder.instance;}}
2. 不变模式
不变模式的使用场景需要满足条件:
- 当对象创建之后,其内部状态和数据不再发生改变;
- 对象需要被共享,被多线程频繁访问;
实现不变模式的方式如下:
- 去除setter方法以及所有修改自身属性的方法;
- 将所有属性设置为私有,并用final标记,确保其不可修改;
- 确保没有子类可以重载修改它的行为;
- 有一个可以创建完整对象的构造函数;
public final class Product {private final String no;private final String name;private final String price;public Product(String no, String name, String price) {super();this.no = no;this.name = name;this.price = price;}public String getNo() {return no;}public String getName() {return name;}public String getPrice() {return price;}}
- 生产者-消费者模式
使用BufferingQueue实现。
- 无锁的缓存架构Disruptor
public class LongEvent {private long value;public void set(long value) {this.value = value;}public long getValue() {return value;}}
public class LongEventFactory implements EventFactory<LongEvent> {public LongEvent newInstance() {return new LongEvent();}}public class LongEventHandler implements EventHandler<LongEvent> {public void onEvent(LongEvent event, long sequence, boolean endOfBatch) {System.out.println("Event: " + event.getValue());}}public class LongEventProducer {private final RingBuffer<LongEvent> ringBuffer;public LongEventProducer(RingBuffer<LongEvent> ringBuffer) {this.ringBuffer = ringBuffer;}/* 3.0之前的方法public void onData(ByteBuffer bb) {long sequence = ringBuffer.next();try {LongEvent event = ringBuffer.get(sequence);event.set(bb.getLong(0));} finally {ringBuffer.publish(sequence);}}*/private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR_ONE_ARG = new EventTranslatorOneArg<LongEvent, ByteBuffer>() {@Overridepublic void translateTo(LongEvent longEvent, long l, ByteBuffer byteBuffer) {longEvent.set(byteBuffer.getLong(0));}};public void onData(ByteBuffer byteBuffer) {ringBuffer.publishEvent(TRANSLATOR_ONE_ARG, byteBuffer);}}
public class Main {public static void main(String[] args) throws Exception {Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(new LongEventFactory(),1024, //RingBuffer的大小Executors.newCachedThreadPool(), //消费者线程池ProducerType.MULTI, //支持多事件发布者new BlockingWaitStrategy());RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();disruptor.handleEventsWith(new LongEventHandler(),new LongEventHandler(),new LongEventHandler(),new LongEventHandler());disruptor.start();LongEventProducer producer = new LongEventProducer(ringBuffer);ByteBuffer bb = ByteBuffer.allocate(8);for (long l = 0; true; l++) {bb.putLong(0, l);producer.onData(bb);Thread.sleep(1000);}}}