线程
* 1、继承Thread
* 2、实现Runnable接口
* 3、实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
* 4、线程池
第一种:继承Thread
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main...start...");
Thread01 thread01 = new Thread01();
thread01.start();//启动线程
System.out.println("main...end...");
}
/**
* 1、继承Thread
*/
public static class Thread01 extends Thread{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果=" + i);
}
}
第一种运行结果:
main...start...
main...end...
当前线程:11
运行结果=5
第二种:实现Runnable接口
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main...start...");
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
System.out.println("main...end...");
}
/**
* 2、实现Runnable接口
*/
public static class Runnable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果=" + i);
}
}
}
第二种运行结果:
main...start...
main...end...
当前线程:11
运行结果=5
第三种:实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
public class ThreadTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start...");
FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable01());
new Thread(integerFutureTask).start();
//阻塞等待整个线程执行完成,获取返回结果
Integer integer = integerFutureTask.get();
System.out.println("main...end..."+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;
}
}
}
第三种运行结果:
main...start...
当前线程:11
运行结果=5
main...end...5
以上三种启动线程的方式都不用,浪费资源
【将所有的多线程异步任务都交给线程池执行】
第四种:线程池
给线程池直接提交任务
public class ThreadTest {
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
//当前系统中池只有一两个,每个异步任务,提交给线程池让他自己执行
// ExecutorService service = Executors.newFixedThreadPool(10);
System.out.println("main...stater...");
service.execute(new Runnable01());
System.out.println("main...end...");
}
public static class Runnable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果=" + i);
}
}
}
第四种运行结果:
main...stater...
main...end...
当前线程:11
运行结果=5
区别:
- 继承Thread、实现Runnable接口 不能得到返回值。实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
- 继承Thread、实现Runnable接口、实现Callable接口 都不能控制资源,一运行就会new,会导致资源耗尽
- 线程池可以控制资源
线程池【ExecutorService】的创建:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
1、七大参数:
- corePoolSize:核心线程数;
- maximumPoolSize:最大线程数。控制资源;
- keepAliveTime:存活时间。如果当前的线程数量大于core数量
释放空间的线程(maximumPoolSize-keepAliveTime),只要线程空闲大于指定的keepAliveTime; - unit:时间单位;
- workQueue:阻塞队列。任务大于线程时,会将任务存放再队列中。当线程空闲时就会从队列取出新的任务继续执行;
- threadFactory:线程的创建工厂;
- RejectedExecutionHandler handler:如果队列满了,按照指定的拒绝策略,拒绝执行任务;
2、工作顺序
- 线程池创建,准备好core数量的核心线程,准备接受任务
- corePoolSize满了,就将再进来的任务放入workQueue阻塞队列中。空闲的corePoolSize就会自己去阻塞队列获取任务执行
- workQueue阻塞队列满了,就直接开新线程执行,最大只能开到maximumPoolSize指定的数量
- maximumPoolSize都执行好了,max-core数量空闲的线程会在keepAliveTime指定的时间后自动销毁,最终保持core大小
- 如果corePoolSize开到了maximumPoolSize的数量,还有新任务进来就会使用handler指定的拒绝策略进行处理
使用线程池的原因
- 降低资源的消耗
- 提高响应速度
- 提高线程的可管理性