1.CountDownLatch
允许一个或多个线程等待其他线程完成操作。
CountDownLatch的单参构造传入count,因此只能限制count个线程(即countDown()调用count次,不能多也不能少)。让主线程和t3线程等待t1和t2线程先完成操作。
//需要2个线程先完成操作
static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("线程t1操作");
//t1线程完成操作后,count减1
countDownLatch.countDown();
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println("线程t2操作");
//t2线程完成操作后,count减1
countDownLatch.countDown();
}, "t2");
Thread t3 = new Thread(() -> {
try {
//当count==0时,解除阻塞(t1,t2线程先完成操作)
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程t3操作");
}, "t3");
//三线程并发执行
t1.start();
t2.start();
t3.start();
//让主线程等待其他线程完成操作 当count==0时,解除阻塞(t1,t2线程先完成操作)
countDownLatch.await();
System.out.println("t1,t2已完成操作");
2.CyclicBarrier
CyclicBarrier 让一组线程到达一个屏障时阻塞,直到最后一个线程到达屏障后,被阻塞的线程组并发执行。利用await()方法阻塞线程。
//定义2个线程到达屏障前,执行任务
static CyclicBarrier cyclicBarrier = new CyclicBarrier(3,()->{
System.out.println("该任务先于线程t1,t2执行");
});
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
//线程1到达屏障
cyclicBarrier.await();
System.out.println("线程1进行操作");
} catch (Exception e) {
e.printStackTrace();
}
}, "t1");
Thread t2 = new Thread(() -> {
try {
//线程2到达屏障
cyclicBarrier.await();
System.out.println("线程2进行操作");
} catch (Exception e) {
e.printStackTrace();
}
}, "t2");
Thread t3 = new Thread(() -> {
try {
//线程3到达屏障
cyclicBarrier.await();
System.out.println("线程3进行操作");
} catch (Exception e) {
e.printStackTrace();
}
}, "t3");
Thread t4 = new Thread(() -> {
try {
//线程4到达屏障
cyclicBarrier.await();
System.out.println("线程4进行操作");
} catch (Exception e) {
e.printStackTrace();
}
}, "t4");
Thread t5 = new Thread(() -> {
try {
//线程5到达屏障
cyclicBarrier.await();
System.out.println("线程5进行操作");
} catch (Exception e) {
e.printStackTrace();
}
}, "t5");
t1.start();
t2.start();
//CyclicBarrier重用性。线程3,4可以继续使用该对象
Thread.sleep(3000);
t3.start();
t4.start();
//reset()方法会使屏障前等待的线程抛出异常
t5.start();
Thread.sleep(3000);
cyclicBarrier.reset();
}
3.Semaphore
Semaphore用来控制同时访问资源的线程数量。控制并发数。
//控制并发数3
static Semaphore semaphore = new Semaphore(3);
public static void main(String[] args){
//30个线程并发
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 30; i++) {
final int num = i;
threads.add(new Thread(()->{
try {
//获取许可
semaphore.acquire();
Thread.sleep(3000);
System.out.println("线程t"+num+"开始操作");
//释放许可
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
}
threads.stream().forEach(x->x.start());
3.Exchanger
Exchanger 用于两个线程之间交换数据。 V exchange(V x)方法会阻塞线程,直到另一个线程也执行了exchange(V x)方法。
4.线程池
//package org.apache.tomcat.util.threads;
ThreadPoolExecutor(int corePoolSize,//核心线程数 ,tomcat默认10个
int maximumPoolSize,//最大线程数,tomcat默认200
long keepAliveTime,//最大空闲时间,闲置线程的最大存活时间 tomcat默认60s
TimeUnit unit,//时间单位 纳秒
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory, //线程工厂 tomcat默认线程前缀http-nio-8080-exec-
//饱和处理机制 tomcat默认 RejectHandler拒绝,报异常RejectedExecutionException
RejectedExecutionHandler handler);
allowCoreThreadTimeOut 是否允许销毁核心线程,tomcat 默认false
workers 工作线程HashSet<Worker>,存放的是线程。最大值为maximumPoolSize
workersQueue 任务链表队列(7992) + maximumPoolSize核心线程数(200) = maxConnections最大连接(8192) //tomcat9.0.0以上默认值,大于maximumPoolSize值时,创建workersQueue
acceptCount(100) accept队列到达acceptCount之后,进来的请求会执行RejectHandler(服务器同时接受请求acceptCount+maxConnections) 。
//向线程池提交一个请求时,线程池的execute()主要流程
1.判断线程池里的核心线程数是否都在执行任务,如果不是,则新建线程来执行任务。是,则进入下一环节。
2.判断工作队列是否已满,如果不是,则新提交的任务储存在工作队列中。是,则进入下一环节。
3.判断线程池是否达到最大线程数,如果不是,则创建线程来执行任务。是,则交给饱和策略。
//饱和策略接口,实现该接口处理任务。 Runnable接口的实现类NioEndpoint.SocketProcessor
public interface RejectedExecutionHandler{
void rejectedExecution(Runnable r,ThreadPoolExecutor executor);
}
AbortPolicy 丢弃任务并抛出RejectedExecutionException异常。
DiscardPolicy:丢弃任务,但是不抛出异常。
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
5.Executor
//创建固定数量的线程池 LinkedBlockingQueue无界所以不会拒绝任务 coreThread==maximumPoolSize
Executors.newFixedThreadPool(2);
//创建有一个线程work的线程池 LinkedBlockingQueue所以不会拒绝任务 coreThread==maximumPoolSize=1
Executors.newSingleThreadExecutor();
//创建一个根据需要创建线程60s的线程池,SynchronousQueue coreThread=0,maximumPoolSize=Integer.MAX_VALUE
//特点,线程无限创建
Executors.newCachedThreadPool();
//创建核心线程数为2,最大线程数Integer.MAX_VALUE,阻塞队列DelayedWorkQueue
new ScheduledThreadPoolExecutor(2);
//scheduleFixedDelay() //超过定时周期period,则当前任务结束后会立即执行
//scheduleWithFixedDelay() //延时是相对当前任务结束为起点计算开始时间
6.定时器Timer
//schedule(TimerTask task, long delay)//在延时固定时间执行任务
//schedule(TimerTask task, long delay, long period) //在delay后执行任务,之后每个period执行任务
//scheduleAtFixedRate(TimerTask task, long delay, long period) //与上一个基本相同,不同的是它是相对于初始执行计划的调度。