J.U.C系列(整体架构)

本文深入解析Java中的并发工具,包括线程池Executors的各种类型,如单一线程、缓存线程池等;Exchanger用于线程间数据交换;Semaphore控制资源访问;CyclicBarrier同步线程;ReentrantLock与Condition的高级锁机制;ReadWriteLock的读写锁优化;LockSupport的线程阻塞管理。这些工具在高并发场景下提供了强大的控制能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、J.U.C整理架构图

2、Tools

2.1、Executors

Executors是一个线程池工具类

包含以下几个静态方法

A.newSingleThreadExecutor

单个线程的线程池。

B.newCachedThreadPool

这是一个可缓存的线程池,如果没有线程池中没有线程则自动创建。

C.newFixedThreadPool

固定长度的线程池。

D.newWorkStealingPool

使用SynchronousQueue阻塞队列的线程池。

2.2、Exchager

这里只介绍单槽交换,此类主要用户两个线程用来交换对象,例如:一个工厂线程负责生产对象(生产比较耗费资源),一个线程负责消费,将生产的对象传给此线程消费。只能用来两个线程交换,不能指定线程。

 

public class GradleTest {

    static final CountDownLatch countDownLatch = new CountDownLatch(4);

    static ExecutorService executorService = Executors.newCachedThreadPool();

    static final Exchanger<String> exchanger=new Exchanger<String>();

    static final Runnable run1 = ()->{
        try {
            String result = exchanger.exchange(Thread.currentThread().getName());
            System.out.println("this is "+Thread.currentThread().getName()+" receive data:"+result);
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    };

    static final Runnable run2 = ()->{
        try {
            String result = exchanger.exchange(Thread.currentThread().getName());
            System.out.println("this is "+Thread.currentThread().getName()+" receive data:"+result);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        countDownLatch.countDown();
    };

    static final Runnable run3 = ()->{
        try {
            String result = exchanger.exchange(Thread.currentThread().getName());
            System.out.println("this is "+Thread.currentThread().getName()+" receive data:"+result);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        countDownLatch.countDown();
    };

    static final Runnable run4 = ()->{
        try {
            String result = exchanger.exchange(Thread.currentThread().getName());
            System.out.println("this is "+Thread.currentThread().getName()+" receive data:"+result);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        countDownLatch.countDown();
    };


    @Test
    public void testExchanger(){
        executorService.execute(run1);
        executorService.execute(run2);
        executorService.execute(run3);
        executorService.execute(run3);


        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

 

2.3、Semaphore

Semaphore经常用于限制获取某种资源的线程数量。

以使用工具为例:因为只有2个工具,所以当大家申请工具的时候,最多允许两个线程同时使用工具。

下面代码我们看到,同时有5个线程申请两个工具,所以我们必须限制线程申请。当2个线程已经申请到工具

semaphore.acquire()

其他线程处于等待状态,等待使用工具的线程释放工具

semaphore.release(1)

 

public class SemaphoreTest {

    static final Semaphore semaphore = new Semaphore(2,true);

    static final Tools[] toolsArray = new Tools[]{new Tools(1), new Tools(2)};

    static ExecutorService executorService = Executors.newCachedThreadPool();

    static final CountDownLatch countDownLatch = new CountDownLatch(5);



    static final Runnable fix1 = () -> {
        try {
            System.out.println(Thread.currentThread().getName()+"开始申请工具....");
            long start = System.currentTimeMillis();
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"等待时间为"+(System.currentTimeMillis()-start));
            System.out.println(Thread.currentThread().getName()+"审批通过....");
            Tools unUsedTools = getUnUsedTools();
            System.out.println(Thread.currentThread().getName()+"开始使用工具"+unUsedTools.getNo()+"....");
            TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(2,5));
            realseTools(unUsedTools);
            System.out.println(Thread.currentThread().getName()+"归还工具....");
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {

        }
    };

    static Tools getUnUsedTools(){
        for (Tools tools : toolsArray){
            if(!tools.isUsed()){
                tools.setUsed(true);
                return tools;
            }
        }
        return null;
    }

    static void realseTools(Tools tools){
        tools.setUsed(false);
        semaphore.release(1);
    }

    @Test
    public void testSemaphore() {
        executorService.execute(fix1);
        executorService.execute(fix1);
        executorService.execute(fix1);
        executorService.execute(fix1);
        executorService.execute(fix1);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

2.4 CyclicBarrier

CyclicBarrier为线程设立屏障,当所有线程到达屏障时才继续往下执行操作。
public class CyclicBarrierTest {

    static final Runnable together = () -> {
        System.out.println("大家一起出发去机场!");
    };

    static final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, together);

    static ExecutorService executorService = Executors.newCachedThreadPool();

    static final CountDownLatch countDownLatch = new CountDownLatch(5);

    static final Runnable run = ()->{
        System.out.println(Thread.currentThread().getName()+"到集合地点集合");
        try {
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName()+"到达机场开始登机");
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    };

    @Test
    public void testCyclicBarrier() {
        executorService.execute(new Thread(run,"张三"));
        executorService.execute(new Thread(run,"李四"));
        executorService.execute(new Thread(run,"王五"));
        executorService.execute(new Thread(run,"赵六"));
        executorService.execute(new Thread(run,"唐七"));
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

 

3、Locks

3.1、ReentrantLock重入锁

在JDK5.0以前ReentrantLock的性能优于synchronized,但是在JDK6.0以后的版本两者的性能相差无几。ReentrantLock提供了比synchronized能加灵活的操作方式。

public class ReentrantLockTest {

    static final Lock lock = new ReentrantLock(false);

    static ExecutorService executorService = Executors.newCachedThreadPool();

    static final CountDownLatch countDownLatch = new CountDownLatch(5);

    static final Runnable run = ()->{
        try {
            lock.lockInterruptibly();
            System.out.println(Thread.currentThread().getName()+"获取锁");
            TimeUnit.SECONDS.sleep(2);
            lock.lockInterruptibly();
            System.out.println(Thread.currentThread().getName()+"再次获取锁");
            TimeUnit.SECONDS.sleep(2);
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"释放锁");
        }
    };

    @Test
    public void testReentrantLock(){
        executorService.execute(run);
        executorService.execute(run);
        executorService.execute(run);
        executorService.execute(run);
        executorService.execute(run);

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

 

3.2、Condition

condition是在JDK5.0之后才出现,他是用来替代传统的synchronized加Object的wait()和notify()方法的。

public class ConditionTest {

    //公平锁
    static final Lock lock = new ReentrantLock(true);

    static final Condition empty = lock.newCondition();

    static final Condition full = lock.newCondition();

    //生成容器
    static LinkedList<Integer> container = new LinkedList<Integer>();

    //已生成的数量
    static volatile int hadProductNum = 0;

    //已消费的数量
    static volatile int hadConsumeNum = 0;

    //容器最大数量
    static final int maxContainerSize = 3;

    //允许生成的最大数量
    static final int maxNum = 20;

    //工厂
    static AtomicInteger factory = new AtomicInteger();


    static class Producer implements Runnable {

        @Override
        public void run() {
            for (; ; ) {
                lock.lock();
                try {
                    //容器满了则停止生产等待通知
                    if (container.size() == maxContainerSize) {
                        System.out.println(Thread.currentThread().getName() + "容器满了休眠");
                        full.await();
                    }
                    if (hadProductNum == maxNum) {
                        System.out.println(Thread.currentThread().getName() + "达到生成上限退出");
                        return;
                    }
                    int product = factory.incrementAndGet();
                    container.addLast(product);
                    System.out.println(Thread.currentThread().getName() + " 生成 " + product);
                    hadProductNum++;
                    empty.signal();
                } catch (InterruptedException e) {
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    static class Consumer implements Runnable {

        @Override
        public void run() {
            for (; ; ) {
                lock.lock();
                try {
                    if (hadConsumeNum == maxNum) {
                        System.out.println(Thread.currentThread().getName() + "以消费所有退出");
                        return;
                    }
                    //容器没有数据则休息一会
                    if (container.isEmpty()) {
                        System.out.println(Thread.currentThread().getName() + "容器为空休眠");
                        empty.await(2, TimeUnit.SECONDS);
                    }

                    Integer product = container.removeFirst();
                    System.out.println(Thread.currentThread().getName() + " 消费" + product);
                    hadConsumeNum++;
                    full.signal();
                } catch (InterruptedException e) {
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    @Test
    public void testCondition(){
        Thread p1 = new Thread(new Producer(), "p-1");
        Thread p2 = new Thread(new Producer(), "p-2");
        Thread p3 = new Thread(new Producer(), "p-3");

        Thread c1 = new Thread(new Consumer(), "c-1");
        Thread c2 = new Thread(new Consumer(), "c-2");
        Thread c3 = new Thread(new Consumer(), "c-3");

        c1.start();
        c2.start();
        c3.start();
        p1.start();
        p2.start();
        p3.start();
        try{
            c1.join();
            c2.join();
            c3.join();
            p1.join();
            p2.join();
            p3.join();
        }catch(Exception e){

        }
        System.out.println(" 完成. ");
    }
}

4、ReadWriteLock

4.1、ReentrantReadWriteLock

ReentrantReadWriteLock是da有ReentrantLock语义的读写锁

 (a).重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想。 
 (b).WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有。反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(a),呵呵. 
 (c).ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。 
 (d).不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致。 
(e).WriteLock支持Condition并且与ReentrantLock语义一致,而ReadLock则不能使用Condition,否则抛出UnsupportedOperationException异常。

5、LockSupport

LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞,实现的阻塞和解除阻塞是基于”许可(permit)”作为关联,permit相当于一个信号量(0,1),默认是0. 线程之间不再需要一个Object或者其它变量来存储状态,不再需要关心对方的状态.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值