一.并发
主要要学的内容: 1. 并发安全的措施采取,如加锁等
2. 线程的管理,设计线程池等
3. 线程之间的协作
二. 线程池
线程池适合应用的场景: 1. 服务器接收的大量请求的处理
1. 几个主要概念
corePoolSize,核心线程数,指线程池实际可运行的线程数
maxPoolSize,最大线程数,指实际可运行的线程数的可增加最大数keepAliveTime 超过核心线程数的线程,当空闲时的可存活时间
workQuery,任务存储队列,指任务的缓冲区,当池中的corePoolSize已满时,任务添加到队列中,当队列满时,再去增加可运行线程数,最大至最大线程数,当最大线程数也已经满时,就需要下面的拒绝策略
handler, 最大线程数也满时,对新进的任务的拒绝策略
threadFactory,线程工厂,来产生新的线程
2.线程池种类
FixedThreadPool,核心线程数和最大线程数一致,队列采取LinkedBlockingQueue,属于无界队列,除非内存溢出,否则会一直添加任务
SingleThreadPool,核心线程数和最大线程数都为1,队列同样为无界队列
CacheThreadPool,核心线程数为0,最大线程数为最大整数值,队列为直接队列,即只放一个,相当于池中可放下所有线程,并到最后运行后全部清除掉
ScheduThreadPool,可定时周期性执行任务的线程池。核心线程数指定,最大线程数为最大整数。可用来定时重复执行同一个任务。
3.线程池的关闭
3.1. shutdown ,不再接收新的任务,将会执行完正在执行中的线程以及队列中的任务
3.2. shutdownNow,将执行中的线程立刻停止,使用中断信号,队列中的以列表返回
4.线程池拒绝策略
4.1. 拒绝的发生场景: a. 线程池关闭后,有新任务进来,拒绝;b. 线程池已经达到最大线程数以及队列已满时,有新任务进来,拒绝
4.2. 拒绝策略种类
AbortPolicy: 抛出异常
DiscardPolicy: 直接忽视掉新的任务
DiscardOldestPolicy: 忽视掉最老的任务
CallerRunsPolicy:有任务的发起线程去执行任务,而不是由线程池里的线程执行
三.使用代码示例
package ThreadPool;
import java.util.concurrent.*;
/**
* 线程池的练习
*/
public class ThreadPoolTest1 {
public static volatile int num=0;
public static void main(String[] args) {
Executors.newFixedThreadPool(2);
Executors.newSingleThreadExecutor();
Executors.newCachedThreadPool();
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
//延迟两秒执行,执行一次
scheduledExecutorService.schedule(new Task(),2, TimeUnit.SECONDS);
//一秒后开始执行,没两秒执行一次,执行多次
scheduledExecutorService.scheduleAtFixedRate(new Task(),1,2,TimeUnit.SECONDS);
}
}
class Task implements Runnable{
@Override
public void run() {
ThreadPoolTest1.num++;
System.out.println(System.currentTimeMillis());
System.out.println(ThreadPoolTest1.num);
}
}
package ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 对多线程的练习:创建多线程、创建线程池
*/
public class ThreadPoolTest2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for(int i=0;i<10;i++){
/**
* 假设这里是tomcat服务器的请求处理代码,这里每接受一个请求就创建一个线程来处理,不同请求带的数据不一样
* 所以要保证多个线程间的数据安全
*/
executorService.execute(new myTask(i));
}
}
}
class myTask implements Runnable{
private int num = 0;
myTask(int num){
this.num = num;
}
@Override
public void run() {
System.out.println("线程: "+ Thread.currentThread().getName()+"; num:"+num);
}
}