1: 继承Thread
public static void main(String[] args) throws ExecutionException, InterruptedException{
Thread01 thread01 = new Thread01();
thread01.start();
}
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
}
}
2 :实现Runnable接口
public static void main(String[] args) throws ExecutionException, InterruptedException{
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
}
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
}
}
3 :实现Callable+FutureTask(可以拿到返回结果,可以处理异常)
public static void main(String[] args) throws ExecutionException, InterruptedException{
Callable01 callable01 = new Callable01();
FutureTask<Integer> integerFutureTask = new FutureTask<>(callable01);
new Thread(integerFutureTask).start();
// 阻塞等待整个线程执行完成 获取返回结果
Integer integer = integerFutureTask.get();
System.out.println("拿到的结果"+integer);
}
public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果" + i);
return i;
}
}
4 线程池
给线程池提交任务 ExecutorService
1. Executors (官方提供的直接创建线程池方式,但是真实项目中不建议使用)
Executors.newCachedThreadPool(); //core是0 所有都可回收
Executors.newFixedThreadPool(10); // 固定大小,core = max;都不可回收
Executors.newScheduledThreadPool(10); // 定时任务的线程池
Executors.newSingleThreadExecutor(); // 单线程的线程池
2. new ThreadPoolExecutor
七大参数:
1.corePoolSize:核心线程数;线程池创建好以后就准备就绪的线程数量,就等待来接受异步任务去执行
2.maximumPoolSize 最大线程数量 控制资源
3. keepAliveTime 存活时间。如果当前的线程数量大于core数量 释放空闲的线程(maximumPoolSize - corePoolSize)。
只要线程空闲大于指定的keepAliveTime 相当于将临时工解雇
4. unit 时间单位
5. workQueue 阻塞队列。 如果任务有很多,就会将目前多的任务放在队里里面,只要有线程空闲了,就会去队列取出新的任务继续执行。
6. threadFactory 线程的创建工厂
7. handler 如果队列满了 按照指定的拒绝策略 拒绝我们执行的任务
运行流程:
1.线程池创建,准备好core数量的核心线程,准备接受任务
2.新的任务进来,用core准备好的空闲线程执行
1.core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
2.阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
3.max都执行好了。Max - core数量空闲的线程会在keepAliveTime指定的时间后自动销毁。最终保持到core大小。
4.如果线程数开到了max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理
3.所有的线程都是由指定的factory创建的。
面试题:
一个线程池,core:7 max:20 queue: 50 100并发进来如何分配
7个会立即得到执行,50个会进入队列 再开13个进行执行 剩下的30个就使用拒绝策略
开发中为什么要使用线程池
降低资源的消耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
提交响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
提高线程的可管理性
线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,
还降低系统的稳定性,使用线程池进行统一分配。
区别:
1.2 不能得到返回值 3,可以获取返回值
1.2.3 都不能控制资源
4可以控制资源 性能稳定