一、使用Executors创建线程池:
Executors类提供工厂方法用来创建不同类型的线程池:
ExecutorService executorService = Executors.具体类型的线程池;
通过调用返回值ExecutorService接口的基础方法execute或submit,将具体执行的线程任务传入到线程池中并执行。
线程任务的创建:跳转链接(下面例子都以Runnable接口为例)。
1)newCachedThreadPool
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有60s未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("newCachedThreadPool");
}
});
2)newFixedThreadPool
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数nThreads线程会处于处理任务的活跃状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新的线程将代替它执行后续的任务(如果需要)。在某个线程被显示地关闭之前,池中的线程将一直存在。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
fixedThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("newFixedThreadPool");
}
});
3)newSingleThreadExecutor
创建一个只有一个线程的线程池,这个线程池可以在线程死亡后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去。
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
singleThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("newSingleThreadExecutor");
}
});
4)newScheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3);
scheduledThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("");
}
});
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("延迟三秒,只执行一次");
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("延迟一秒后,每三秒执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("延迟一秒后,等当前任务执行完毕后,推迟三秒后再执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
- schedule方法是创建并执行在给定延迟后启用的一次性 *** 作,只执行一次,第一个参数可以传入Callable接口或Runnable接口。
- scheduleAtFixedRate方法是固定的频率来执行某项计划,它不受每次计划执行时间的影响。到时间,它就执行;
- scheduleWithFixedDelay方法,是相对任务。即无论当前任务执行多长时间,等执行完了,我再延迟指定的时间后再执行下一次,它受计划执行时间的影响。
5)newSingleThreadScheduledExecutor
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
注意:如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,和newSingleThreadExecutor一样,一个新线程会代替它执行后续的任务。
可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newScheduledThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
和newScheduledThreadPool相同底层都是通过ScheduledThreadPoolExecutor实现的,所以也有对应的schedule、scheduleAtFixedRate和scheduleWithFixedDelay方法。
6)newWorkStealingPool
newWorkStealingPool是JDK1.8新增的线程池实现,通过原码可以看出上述线程池底层都是通过ScheduledThreadPoolExecutor或ThreadPoolExecutor类实现的,和其它线程池不同的是它底层是通过ForkJoinPool类实现的。
ThreadPoolExecutor和ForkJoinPool类一样都继承自AbstractExecutorService抽象类。
使用newWorkStealingPool的好处是:把1个任务拆分成多个“小任务”,把这些“小任务”分发到多个线程上执行。这些“小任务”都执行完成后,再将结果合并。
之前的线程池中,多个线程共有一个阻塞队列,而newWorkStealingPool 中每一个线程都有一个自己的队列。
当线程发现自己的队列没有任务了,就会到别的线程的队列里获取任务执行。可以简单理解为”窃取“。
一般是自己的本地队列采取LIFO(后进先出),窃取时采用FIFO(先进先出),一个从头开始执行,一个从尾部开始执行,由于偷取的动作十分快速,会大量降低这种冲突,也是一种优化方式。
它有两种具体的构造方法:
1、无参:
Runtime.getRuntime().availableProcessors()是获取当前系统可以的CPU核心数。
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
2、有参:
就一个参数parallelism,可以自定义并行度。
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
即:如果传入具体的参数则会创建相应的线程数,如果没有定义,则会创建系统CPU核心数对应的线程数。
三、停止线程池:
shutdown()方法调用后,线程池不再接收新任务,并且会将线程池中所有的任务执行后自动停止。
shutdownNow()方法调用后,线程池会强制中断所有线程立即停止。
四、线程池的ThreadFactory:
ThreadFactory简单来说就是用来创建线程的,其中也只是有一个newthread方法。
一些常用的作用:
- 给线程命名,查看创建线程数
- 给线程设置是否是后台运行
- 设置线程优先级
1)创建ThreadFactory的实现(也可以直接使用匿名内部类的方式实现)
public class MyThreadFactory implements ThreadFactory{
private final boolean isDaemon;
MyThreadFactory(boolean isDaemon){
this.isDaemon = isDaemon;
}
@Override
public Thread newThread(Runnable r) {
Thread newThread = new Thread(r);
newThread.setDaemon(isDaemon);
return newThread;
}
}
2)将ThreadFactory传入线程池:
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3,
new MyThreadFactory(true));
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("");
}
});
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)