创建一个线程类并继承Thread ,并覆盖run方法,然后在启动线程的时候调用start
public class MyThread extends Thread {public MyThread() {}public void run() {for(int i = 0; i < 10; i ++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}public static void main(String[] args) {MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();MyThread myThread3 = new MyThread();myThread1.start();myThread2.start();myThread3.start();}
}
创建一个线程类并实现Runnable接口 ,并实现run方法,然后在启动线程的时候调用start
public class MyRunable implements Runnable{public void run() {for(int i = 0; i < 10; i ++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}public static void main(String[] args) {MyRunable myRun = new MyRunable();MyThread myThread1 = new Thread(myRun);MyThread myThread2 = new Thread(myRun);MyThread myThread3 = new Thread(myRun);myThread1.start();myThread2.start();myThread3.start();}
}
创建一个线程类,实现Callable接口,并实现call方法,然后在启动线程的时候调用start
callable接口是有返回值的,借助FutureTask类能够实现判断任务是否中断,中断任务以及任务是否完成
public class MyCallnable implements Callable {public String call() throws Exception {for (int i = 0; i < 10; i++) {System.out.println("myCallable线程正在执行:"+i);}return "MyCallabe线程执行完毕";}public static void main(String[] args) {//创建futuretask对象FutureTask futureTask = new FutureTask(new MyCallnable());//创建Thread对象,传入futureTaskThread thread1 = new Thread(futureTask);Thread thread2 = new Thread(futureTask);Thread thread3 = new Thread(futureTask);thread1.start();thread2.start();thread3.start();}
}
Executors提供五种线程池,分别为:
下面我们就来重点说下线程池
通常我们使用线程的时候就去创建一个线程,执行完了然后再回收释放资源,但是就会有一个问题:
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程释放线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务,其他的任务就可以复用现成的线程资源,不必再创建销毁,浪费系统资源,那么就有了线程池这个东西。
Executors提供五种线程池,分别为:
corePoolSize(线程池基本大小):当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时,(除了利用提交新任务来创建和启动线程(按需构造),也可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。)
maximumPoolSize(线程池最大大小):线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数。
keepAliveTime(线程存活保持时间)当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。
workQueue(任务队列):用于传输和保存等待执行任务的阻塞队列。
threadFactory(线程工厂):用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。
handler(线程饱和策略):当线程池和队列都满了,再加入线程会执行此策略。
1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,释放空闲线程
6.当设置allowCoreThreadTimeOut(true)时,该参数默认false,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:是一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
SynchronousQueue:是一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
PriorityBlockingQueue:是一个具有优先级的无限阻塞队列。
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略: