一、两种线程模型
线程是调度CPU的最小单元,也叫轻量级进程LWP(Light Weight Process)。
用户级线程(ULT):用户程序实现,不依赖操作系统核心,应用程序提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快。内核对ULT无感知,线程阻塞则进程(包括它的所有线程)阻塞。
内核级线程(KLT):系统内核管理线程(KLT),内核保存线程的状态和上下文细信息,线程阻塞不会引起进程阻塞。在处理器系统上,多线程在处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快。
二、Java线程与系统内核线程
Java虚拟机使用的是哪一种线程模型?
JVM使用的线程模型:KLT。
三、线程池的意义
线程是稀缺资源,它的创建与销毁是一个相对偏重且消耗资源的操作,而Java线程依赖于内核线程,创建线程需要进行操作系统状态切换,为避免资源过度销毁需要设法重用线程执行多个任务。线程池就是一个线程缓存,负责对线程进行统一分配、调度与监控。
什么时候使用线程池?
- 单个任务处理时间比较短。
- 需要处理的任务数量很大。
线程池的优势?
- 重用存在的线程,减少线程创建,消亡的开销,提高性能。
- 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立执行。
- 提高线程的客管理性,可统一分配,调优和监控。
四、线程池的创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ThreadPoolDemo {
public static void main(String[] args) {
//创建一个缓存线程池,当线程数过大,可回收多余线程,如线程数不足,创建新线程
ExecutorService executorService = Executors.newCachedThreadPool();
//创建一个固定数量大小的线程池,当线程任务数超过固定大小时,未执行的线程任务进行阻塞队列,等待线程池调度
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
//创建一个单例线程池, 只存在一个线程运行, 多的线程任务进行阻塞状态
ExecutorService executorService3 = Executors.newSingleThreadExecutor();
//创建一个定时调度线程池,内置一个延迟队列,可按照设定的固定时间周期性的执行任务
ScheduledExecutorService executorService4 = Executors.newScheduledThreadPool(10);
for (int i = 0; i < 10; i++) {
final int idx = i;
executorService.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
@Override
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
}
});
}
executorService.shutdown(); // 关闭线程池
}
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, //核心线程数
Integer.MAX_VALUE, //非核心线程数
60L, //保活时间
TimeUnit.SECONDS, //时间单位
new SynchronousQueue<Runnable>()); //队列
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public ThreadPoolExecutor(int corePoolSize, //核心线程
int maximumPoolSize, //非核心线程
long keepAliveTime, //保活时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //队列
ThreadFactory threadFactory, //线程工厂
RejectedExecutionHandler handler //拒绝策略
) {}
提交优先级:核心线程>>>队列>>>非核心线程
执行优先级:核心线程>>>非核心线程>>>队列
阻塞队列:在任意时刻,不管并发有多高,永远只有一个线程能够进行队列的入队或出队操作(FIFO),也是线程安全队列。