初始化线程的 4 种方式
1、继承Thread
public void thread(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main....start....");
/**
* 1)、继承Thread
* Thread01 thread = new Thread01();
* thread.start();//启动线程
*
System.out.println("main....end....");
}
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 void thread(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main....start....");
// 2)、实现Runnable接口
Runable01 runable01 = new Runable01();
new Thread(runable01).start();
System.out.println("main....end....");
}
public static class Runable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:"+Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:"+i);
}
}
3、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)
//源码 返回类型就是泛型类型 并且可以抛出异常
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
public void thread(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main....start....");
// 3)、实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
//阻塞等待整个线程执行完成,获取返回结果
Integer integer = futureTask.get();
}
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、线程池
线程池来初始化线程一般有两种方法,一种是使用它封装的框架Executors直接来创建
但是这种方法是不被推荐的!阿里巴巴规范建议使用原生线程池ThreadPoolExecutor。
Java 多线程:彻底搞懂线程池_孙强 Jimmy的博客-CSDN博客_线程池
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
创建一个新的 ThreadPoolExecutor与给定的初始参数。
参数
corePoolSize - 即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut
maximumPoolSize - 池中允许的最大线程数
keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间。
unit - keepAliveTime参数的时间单位
workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务。
threadFactory - 执行程序创建新线程时使用的工厂
handler - 线程池执行拒绝策略,当线数量达到maximumPoolSize大小,并且workQueue也已经塞满了任务的情况下,线程池会调用handler拒绝策略来处理请求。
异常
IllegalArgumentException - 如果以下某项成立:
corePoolSize < 0
keepAliveTime < 0
maximumPoolSize <= 0
maximumPoolSize < corePoolSize
NullPointerException - 如果 workQueue或 threadFactory或 handler为空
线程先进入core,core满了就放入阻塞队列中,阻塞队列满了就开启max最大线程。如果都满了就进入拒绝策略
* 工作顺序:
* 1)、线程池创建,准备好core数量的核心线程,准备接受任务
* 1.1、core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
* 1.2、阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
* 1.3、max满了就用RejectedExecutionHandler拒绝任务
* 1.4、max都执行完成,有很多空闲.在指定的时间keepAliveTime以后,释放max-core这些线程
*
* new LinkedBlockingDeque<>():默认是Integer的最大值。内存不够
*
* 一个线程池 core 7; max 20 ,queue:50,100并发进来怎么分配的;
* 7个会立即得到执行,50个会进入队列,再开13个进行执行。剩下的30个就使用拒绝策略。
* 如果不想抛弃还要执行。CallerRunsPolicy;
*
*/
为什么不推荐用框架Executors?因为阻塞队列默认就是Integer的最大值!!可能最造成OOM!!