java线程池并行

一:CountDownLatch

1.1:概念

CountDownLatch是在jdk1.5的时候被引入的,位于java.util.concurrent并发包中,CountDownLatch叫做闭锁,也叫门闩。

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。

举个例子,班长和五个同学都在教室里面写作业,班长必须等待五个同学都走了之后,才能把教室门锁上,CountDownLatch就提供了类似这种一个线程需要等待其他线程都执行完成之后,自己再去执行

 

1.2:原理

CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应的减1。当计数器的值减到0时,表示所有的线程都已完成任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务

 

1.3:常用方法

 

 

1.4:使用示例一:主线程等待所有的子线程执行完成后,再执行

 

import org.junit.Test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadTesst01 {

@Test
public void test01() throws InterruptedException {
// 创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 16, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));
int taskCount = 100;
CountDownLatch countDownLatch = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
threadPoolExecutor.submit(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ">>执行结束!");
// 当前线程调用此方法,则计数减一
countDownLatch.countDown();
});
}

// 判断是不是所有任务执行结束
// 阻塞当前线程(此例子就是main主线程),直到计数器的值为0,主线程才开始处理
countDownLatch.await();
System.out.println("执行完成");
}
}

 1.5:使用场景

有时我们想同时启动多个线程,实现最大程度的并行性。如果我们创建一个初始计数器为1的CountDownLatch,多个线程在开始执行任务前首先countdownlatch.awaitO)在这个锁上等待,只需要主线程调用一次countDown(方法就可以让其他所有等待的线程同时恢复执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。

开始执行前等待N个线程完成各自任务后,进行汇总合并:例如,我们需要使用多线程统计完所有的数据之后,做一个汇总,就可以使用CountDownLatch

 

1.6:缺点

CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后不能再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

 

二:Semaphore

java.util.concurrent.Semaphore

参考:https://www.bilibili.com/video/BV1ta41117f9/?spm_id_from=333.337.search-card.all.click&vd_source=aa4e16557c3a6622877c08d8d7a0a57f

2.1:概念

Semaphore是一个计数信号量,是JDK1.5引入的一个并发工具类,位于java.util.concurrent包中。Semaphore翻译成字面意思为“信号量”,可以控制同时访问资源的线程个数。

举个例子,公园里面的厕所只有5个坑,假如有10个人要上厕所的话,那么同时能去上厕所的人就只能有5个,还剩下5个人只能在外面等待。当5个人中有任何一个人离开后,其中在等待的五个人中又有一个人可以使用了,依次下去,直到所有人都上完厕所。

 

2.2:原理

Semphore计数信号量由一个指定数量的“许可"初始化。每调用一次 acquire(),一个许可会被调用线程取走。每调用一次release(),一个许可会被返还给信号量。因此,在没有任何release()调用时,最多有N个线程能够通过acquire()方法,N是该信号量初始化时的许可的指定数量。这些许可只是一个简单的计数器。

可以简单理解为:信号量中有很多n个令牌,每个线程执行任务时,需要先获取到一块令牌才能执行,那么最多就只允许n个线程同时执行任务,其他线程阻塞在那里等待获取令牌。当其他线程执行完任务后,会把令牌还回去,这时候其他线程就可以获取令牌了。

 

2.3:常用方法

 

2.4:测试代码

import org.junit.Test;

import java.util.concurrent.*;

public class ThreadTesst01 {
    
    @Test
    public void test01() {
        // 创建线程池
        int taskCount = 100;
        Semaphore semaphore = new Semaphore(5);
        for (int i = 1; i <= taskCount; i++) {
            new SemaphoreThread(semaphore, i).start();
        }

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

    private class SemaphoreThread extends Thread {
        private Semaphore semaphore;
        private int index;

        public SemaphoreThread (Semaphore semaphore, int index) {
            this.semaphore = semaphore;
            this.index = index;
        }

        @Override
        public void run() {
            try {
                // 获取许可
                semaphore.acquire();
                System.out.println("第"+ index + "个任务开始执行!");
                Thread.sleep(10000);
                System.out.println("第"+ index + "个任务结束执行!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 释放许可
                semaphore.release();
            }
        }
    }
}

 

2.5;使用场景

信号量Semaphore可以用来做限流,控制同时访问资源的线程数量或者用户数量等

 

 

posted @ 2023-03-08 21:08  银河系的极光  阅读(176)  评论(0编辑  收藏  举报