java有四种线程池类型
单线程线程池
将线程提交到线程池中,提交的线程依次执行
Executors.newSingleThreadExecutor()
固定数目线程池
提交到线程池的任务数大于线程池线程数量则等待
Executors.newFixedThreadPool(3)
无界可缓存线程池
创建的线程数量无上限,第二个任务执行时若第一个任务已执行完则第二个任务执行时复用第一个任务执行时的线程。
Executors.newCachedThreadPool()
调度任务线程池
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
service.scheduleAtFixedRate(new MyThread1("线程"+i,i), 1, 1,TimeUnit.SECONDS);
return service;
我们用简单的代码来看下线程池运行的情况
public class executorServiceTest {
public static int number = 100;
public static int i =1;
public static ExecutorService getSingleThreadExecutor() {
return Executors.newSingleThreadExecutor();
}
public static ExecutorService getCachedThreadPool() {
return Executors.newCachedThreadPool();
}
public static ExecutorService getFixedThreadPool() {
return Executors.newFixedThreadPool(3);
};
public static ScheduledExecutorService getScheduledThreadPool() {
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
service.scheduleAtFixedRate(new MyThread1("线程"+i,i), 1, 1,TimeUnit.SECONDS);
return service;
};
public static void main(String[] args) {
// 创建一个可重用固定线程数的线程池
ExecutorService pool = getSingleThreadExecutor();
// 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread1("线程1",1);
t1.setName("线程1");
Thread t2 = new MyThread1("线程2",2);
t2.setName("线程2");
Thread t3 = new MyThread1("线程3,",3);
t3.setName("线程3");
Thread t4 = new MyThread1("线程4",4);
t4.setName("线程4");
Thread t5 = new MyThread1("线程5",5);
t5.setName("线程5");
// 将线程放入池中进行执行 execute没返回值 submit有返回值
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
// 关闭线程池
pool.shutdown();
}
}
class MyThread1 extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
executorServiceTest.number =executorServiceTest.number+ this.plusValue;
executorServiceTest.i = executorServiceTest.i+1;
System.out.println("加数:"+this.plusValue+",当前number的值:"+executorServiceTest.number);
}
private String name;
private int plusValue;
public MyThread1(String name,int plusValue) {
super();
this.name = name;
this.plusValue = plusValue;
}
}
上面代码中的前四个静态方法是获取线程池实例
MyThread1是线程类 name plusValue 两个属性是为了分析代码构造的 通过构造函数给类的域赋值。
先看看单线程运行池的结果
pool-1-thread-1正在执行。。。
加数:1,当前number的值:101
pool-1-thread-1正在执行。。。
加数:2,当前number的值:103
pool-1-thread-1正在执行。。。
加数:3,当前number的值:106
pool-1-thread-1正在执行。。。
加数:4,当前number的值:110
pool-1-thread-1正在执行。。。
加数:5,当前number的值:115
可以看到线程池里只有一个线程 pool-1-thread-1 执行顺序为1 2 3 4 5
加数:1 表示 执行了提交的t1(参照构造函数)
改变提交顺序
pool.execute(t1);
pool.execute(t3);
pool.execute(t2);
pool.execute(t4);
pool.execute(t5);
结果是这样
pool-1-thread-1正在执行。。。
加数:1,当前number的值:101
pool-1-thread-1正在执行。。。
加数:3,当前number的值:104
pool-1-thread-1正在执行。。。
加数:2,当前number的值:106
pool-1-thread-1正在执行。。。
加数:4,当前number的值:110
pool-1-thread-1正在执行。。。
加数:5,当前number的值:115
只是执行的顺序有改变 1 3 2 4 5
可以单线程线程池是依次执行提交的任务 前一个任务没完成后一个任务不会执行
可缓存线程池
如果线程池的大小超过了处理任务所需要的线程,线程60秒内未使用会被回收 ,如果新的任务被提交,线程池内有未使用的线程则线程会被复用。
提交线程
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
第一次执行
pool-1-thread-1正在执行。。。
加数:1,当前number的值:101
pool-1-thread-3正在执行。。。
加数:3,当前number的值:104
pool-1-thread-5正在执行。。。
加数:5,当前number的值:109
pool-1-thread-2正在执行。。。
加数:2,当前number的值:111
pool-1-thread-4正在执行。。。
加数:4,当前number的值:115
第二次执行
pool-1-thread-3正在执行。。。
加数:3,当前number的值:103
pool-1-thread-1正在执行。。。
加数:1,当前number的值:104
pool-1-thread-5正在执行。。。
加数:5,当前number的值:109
pool-1-thread-2正在执行。。。
加数:2,当前number的值:111
pool-1-thread-4正在执行。。。
加数:4,当前number的值:115
两次执行结果不同,再执行一次结果还有可能不同
从这个结果我们看出线程池内有5个线程(我们提交了5个任务),线程得到CPU执行机会是随机的。
我们改变下线程池提交任务的代码(模拟提交任务时线程池内有空闲线程,看是否会被复用)
pool.execute(t1);
pool.execute(t2);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
这里的Thread.sleep(1000)当前线程休眠1秒后在执行后面的提交t3,t4任务,这时执行t1,t2任务的线程 已经执行完但仍保流在线程池中
下面是运行结果
pool-1-thread-1正在执行。。。
加数:1,当前number的值:101
pool-1-thread-2正在执行。。。
加数:2,当前number的值:103
pool-1-thread-3正在执行。。。
加数:5,当前number的值:108
pool-1-thread-2正在执行。。。
加数:3,当前number的值:111
pool-1-thread-1正在执行。。。
加数:4,当前number的值:115
可以看到线程pool-1-thread-1 pool-1-thread-2被复用了
固定数目线程池 运行结果
固定线程池是新来一个任务就会在线程池中创建一个线程,直到达到线程池的数量,线程池的大小一旦达到最大值就会保持不变
比如我们创建一个数目为3的固定线程池,提交两个任务那么线程池里只会有两个线程
提交的任务超过线程池线程数则等待线程池里的任务执行完
定时任务线程池
同时创建多个定时任务线程池可以用来模拟多线程安全
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(new MyThread1("线程"+i,i), 1, 1,TimeUnit.SECONDS);
这里创建的定时任务每1秒执行一次,线程池里只有一个线程。
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
service.scheduleAtFixedRate(new MyThread1("线程"+i,i), 1, 1,TimeUnit.SECONDS);
这样线程池里就有3个线程,把3设为1就跟上面的是一样的效果了