进程和线程的区别
继承Thread类创建
public class TestThread extends Thread {
@Override
public void run() {
System.out.println("Thread");
}
public static void main(String[] args) {
new TestThread().start();
}
}
实现Runable接口创建
public class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable");
}
public static void main(String[] args) {
Thread thread = new Thread(new TestRunnable());
thread.start();
}
}
- 由于JAVA是单继承多实现的特性,线程类实现Runnable后还可以继承其他类或者实现其他接口,使用方式更灵活
实现Callable接口创建
public class TestCallable implements Callable<String> {
public static void main(String[] args) {
FutureTask<String> futureTask = new FutureTask<String>(new TestCallable());
new Thread(futureTask).start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
@Override
public String call() throws Exception {
return "Callable";
}
}
- 除了接口的特性,提供了线程的返回值和异常抛出,可以调用futureTask.get()方法去获取线程异步的执行结果,但是,get方法在线程在执行完之前是阻塞的
通过线程池创建
- 创建固定⼤⼩的线程池
- Executors.newFixedThreadPool
- 创建可缓存的线程池
- Executors.newCachedThreadPool
- 创建单个线程数的线程池
- Executors.newSingleThreadExecutor
- 创建可以执⾏延迟任务的线程池
- Executors.newScheduledThreadPool
- FixedThreadPool 和 SingleThreadPool,允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM
- CachedThreadPool 和 ScheduledThreadPool,允许的创建的最大线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM
- 阿里开发手册提倡使用自定义的线程池
- 使用构造方法创建ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize 线程池中的常驻核心线程数
- maximumPoolSize 线程池能够容纳同时执行的最大线程数,必须大于1
- keepAliveTime 多余的空闲线程的存活时间
- unit 时间单位
- workQueue 任务队列,存放被提交但是未执行的任务
- threadFactory 生成线程池中的线程的线程工厂,用于创建线程,一般用默认的即可
- handler 拒绝策略,当工作线程大于等于最大线程池数,并且工作队列已满,新提交的任务使用拒绝策略处理
- JDK默认的拒绝策略有四种:
- AbortPolicy(默认):直接抛出 RejectedExecutionException 异常阻止系统正常运行
- CallerRunsPolicy:"调用者运行"一种调节机制,该策略既不会拋弃任务,也不会拋出异常,而是将某些任务回退到调用
- DiscardoldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
- DiscardPolicy:直接丢弃任务,不子任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案
线程池的运行原理
-
- 在创建了线程池后,等待提交过来的任务请求。
-
- 当调用 execute( 方法添加一个请求任务时,线程池会做如下判断:
- 2.1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;
- 2.2 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列:
- 2.3 如果这时候队列满了且正在运行的线程数量还小于maximumPoolsize,那么还是要创建非核心线程立刻运行这个任务;
- 2.4 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
-
- 当一个线程完成任务时,它会从队列中取下一个任务来执行。
-
- 当一个线程无事可做超过一定的时间(keepAlive Time)时,线程池会判断:
如果当前运行的线程数大于corePoolsize,那么这个线程就被停掉。
所以线程池的所有任务完成后它最终会收缩到 corePoolsize 的大小。
如有错误请指正,谢谢