常用处理并发的几种方式

直接怼实战代码
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;
    }
}

                
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深藏功与名呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值