直接怼实战代码
package cn.com.project.fw.core.concurrency;
import com.google.common.util.concurrent.RateLimiter;
import org.junit.Test;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 处理并发的几种方法
*/
public class ConcurrencyTest {
private static AtomicInteger atomicInteger = new AtomicInteger();
public static void main(String[] args) {
}
@Test
public void lock() throws InterruptedException {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
new Thread(() -> doAction(lock.writeLock())).start();
new Thread(() -> doAction(lock.writeLock())).start();
new Thread(() -> doAction(lock.writeLock())).start();
Thread.sleep(20000);
}
@Test
public void blockQueue() throws InterruptedException {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(2);
queue.add(atomicInteger.getAndAdd(1));
queue.add(atomicInteger.getAndAdd(1));
new Thread(() -> consumer(queue)).start();
new Thread(() -> consumer(queue)).start();
new Thread(() -> consumer(queue)).start();
new Thread(() -> consumer(queue)).start();
Thread.sleep(10000);
}
@Test
public void semaphore() throws InterruptedException {
Semaphore semaphore = new Semaphore(2);
new Thread(() -> semConsumer(semaphore)).start();
new Thread(() -> semConsumer(semaphore)).start();
new Thread(() -> semConsumer(semaphore)).start();
new Thread(() -> semConsumer(semaphore)).start();
new Thread(() -> semConsumer(semaphore)).start();
Thread.sleep(20_000);
}
@Test
public void testCyclicBarrier() throws InterruptedException {
// 到达两个工作线程才能继续往后面执行
CyclicBarrier barrier = new CyclicBarrier(2);
// 三秒之后,下面两个线程的才会输出 开始执行
new Thread(() -> cyclicBarrierLogic(barrier, 1000)).start();
new Thread(() -> cyclicBarrierLogic(barrier, 3000)).start();
Thread.sleep(4000);
// 重置,可以再次使用
barrier.reset();
new Thread(() -> cyclicBarrierLogic(barrier, 1)).start();
new Thread(() -> cyclicBarrierLogic(barrier, 1)).start();
Thread.sleep(10000);
}
@Test
public void testGuavaRate() throws InterruptedException {
// 1s 中放行两个请求
RateLimiter rateLimiter = RateLimiter.create(2.0d);
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
new Thread(() -> guavaProcess(rateLimiter)).start();
Thread.sleep(20_000);
}
/**
* 计数器 CountDownLatch 方式
* 计数,应用场景更偏向于多线程的协同,比如多个线程执行完毕之后,再处理某些事情;不同于上面的并发数的控制,它和栅栏一样,更多的是行为结果的统一
* 这种场景下的使用姿势一般如下
* 重点:countDownLatch 计数为0时放行
* @throws InterruptedException
*/
@Test
public void countDown() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(() -> {
try {
System.out.println("do something in " + Thread.currentThread());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}).start();
new Thread(() -> {
try {
System.out.println("do something in t2: " + Thread.currentThread());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}).start();
countDownLatch.await();
System.out.printf("结束");
}
/**
* 同步代码块方式
* 只会有一个线程执行
*/
public synchronized void doProcess() {
System.out.println("doProcess");
}
/**
* CAS自旋方式
* 比如 AtomicXXX 原子类中的很多实现,就是借助 unsafe 的 CAS 来实现的
* @return int
*/
public final int getAndIncrement() {
return UnsafeAccessor.getUnsafe().getAndAddInt(1, 2, 1);
}
/**
* 锁方式
* jdk本身提供了不少的锁,为了实现单实例的并发控制,我们需要选择写锁;
* 如果支持多读,单实例写,则可以考虑读写锁;一般使用姿势也比较简单
* @param writeLock 入参
*/
public void doAction(ReentrantReadWriteLock.WriteLock writeLock) {
try {
writeLock.lock();
System.out.println("持有锁成功 " + Thread.currentThread().getName());
Thread.sleep(1000);
System.out.println("执行完毕! " + Thread.currentThread().getName());
writeLock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 阻塞队列方式
* @param queue 入参
*/
private void consumer(LinkedBlockingQueue<Integer> queue) {
try {
// 同步阻塞拿去数据
int val = queue.take();
Thread.sleep(2000);
System.out.println("成功拿到: " + val + " Thread: " + Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 添加数据
System.out.println("结束 " + Thread.currentThread());
queue.offer(atomicInteger.getAndAdd(1));
}
}
/**
* 信号量 Semaphore 方式
* @param semaphore 入参
*/
private void semConsumer(Semaphore semaphore) {
try {
//同步阻塞,尝试获取信号
semaphore.acquire(1);
System.out.println("成功拿到信号,执行: " + Thread.currentThread());
Thread.sleep(2000);
System.out.println("执行完毕,释放信号: " + Thread.currentThread());
semaphore.release(1);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 栅栏 CyclicBarrier 方式
* CyclicBarrier的作用与上面的 CountDownLatch 相似,区别在于正向计数+1, 只有达到条件才放行; 且支持通过调用reset()重置计数,而CountDownLatch则不行
* 一个简单的demo
* @param barrier barrier
* @param sleep sleep
*/
private void cyclicBarrierLogic(CyclicBarrier barrier, long sleep) {
// 等待达到条件才放行
try {
System.out.println("准备执行: " + Thread.currentThread() + " at: " + LocalDateTime.now());
Thread.sleep(sleep);
int index = barrier.await();
System.out.println("开始执行: " + index + " thread: " + Thread.currentThread() + " at: " + LocalDateTime.now());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* guava 令牌桶方式
* guava封装了非常简单的并发控制工具类RateLimiter,作为单机的并发控制首选
* 一个控制qps为2的简单demo如下:
* @param rateLimiter rateLimiter
*/
private void guavaProcess(RateLimiter rateLimiter) {
try {
// 同步阻塞方式获取
System.out.println("准备执行: " + Thread.currentThread() + " > " + LocalDateTime.now());
rateLimiter.acquire();
System.out.println("执行中: " + Thread.currentThread() + " > " + LocalDateTime.now());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 同步代码块(单例)
*/
class Single {
private static volatile Single instance;
private Single() {}
public static Single getInstance() {
if (instance == null) {
synchronized(Single.class) {
if (instance == null) instance = new Single();
}
}
return instance;
}
}
class UnsafeAccessor {
private static Unsafe unsafe;
static {
try {
Field unsafeFile = Unsafe.class.getDeclaredField("theUnsafe");
unsafeFile.setAccessible(true);
//因为是静态属性
unsafe = (Unsafe) unsafeFile.get(null);
}catch (Exception e){}
}
public static Unsafe getUnsafe(){
return unsafe;
}
}