线程池(来自百度百科)
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。任务调度以执行线程的常见方法是使用同步队列,称作任务队列。池中的线程等待队列中的任务,并把执行完的任务放入完成队列中。
常见线程池
在Java中可以使用Executors类来创建线程池,Executors是静态工厂的功能,生产各种类型线程池。
1、newCachedThreadPool
创建一个可缓存的线程池。需要使用到线程时,会先从线程池中查找是否存在空闲的线程,如果没有线程可用,线程池能够根据需求创建新线程并放入线程池中,如果有线程可用,则直接使用可用的线程。线程执行完任务后,不会立即回收,会再次放回线程池,可以重用,缓存的线程60秒未使用则会被终止并移除。该线程池通常用于执行许多短期异步任务,能够有效提高程序的性能。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for(int i = 0;i<10;i++){
final int num = i;
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
}
});
}
cachedThreadPool.shutdown();
System.out.println("main执行完成");
}
}
运行结果:
pool-1-thread-1正在执行,num = 0
pool-1-thread-2正在执行,num = 1
pool-1-thread-1正在执行,num = 7
pool-1-thread-3正在执行,num = 2
pool-1-thread-2正在执行,num = 8
main执行完成
pool-1-thread-4正在执行,num = 3
pool-1-thread-6正在执行,num = 5
pool-1-thread-7正在执行,num = 6
pool-1-thread-5正在执行,num = 4
pool-1-thread-8正在执行,num = 9
每次for循环中Thread.sleep(100);,运行结果:
pool-1-thread-1正在执行,num = 0
pool-1-thread-1正在执行,num = 1
pool-1-thread-1正在执行,num = 2
pool-1-thread-1正在执行,num = 3
pool-1-thread-1正在执行,num = 4
pool-1-thread-1正在执行,num = 5
pool-1-thread-1正在执行,num = 6
pool-1-thread-1正在执行,num = 7
pool-1-thread-1正在执行,num = 8
pool-1-thread-1正在执行,num = 9
main执行完成
2、newFixedThreadPool
创建一个线程数量固定的线程池,线程池会重用运行的线程来执行在共享的无边界队列上的任务。指定的线程数量n即线程的最大并发数,也就是说,在任何时候,至多n个线程主动处理任务。如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待线程可用。如果任何线程在关闭之前的执行过程中由于失败而终止,则在需要执行后续任务时将使用新线程来代替它。线程池中的线程将一直存在,直到主动关闭线程池。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
for(int i = 0;i<10;i++){
final int num = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
}
});
}
fixedThreadPool.shutdown();
System.out.println("main执行完成");
}
}
运行结果:
pool-1-thread-1正在执行,num = 0
pool-1-thread-2正在执行,num = 1
main执行完成
pool-1-thread-3正在执行,num = 2
pool-1-thread-1正在执行,num = 5
pool-1-thread-2正在执行,num = 4
pool-1-thread-2正在执行,num = 8
pool-1-thread-2正在执行,num = 9
pool-1-thread-4正在执行,num = 3
pool-1-thread-1正在执行,num = 7
pool-1-thread-3正在执行,num = 6
3、newSingleThreadExecutor
创建一个单线程的线程池。(无边界队列中)所有任务都是通过这一个线程来执行,所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个单线程由于意外(eg:执行失败)而终止,并且需要执行后续任务,则会新线程将取代它。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for(int i = 0;i<5;i++){
final int num = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
}
});
}
singleThreadPool.shutdown();
System.out.println("main执行完成");
}
}
运行结果:
main执行完成
pool-1-thread-1正在执行,num = 0
pool-1-thread-1正在执行,num = 1
pool-1-thread-1正在执行,num = 2
pool-1-thread-1正在执行,num = 3
pool-1-thread-1正在执行,num = 4
4、newScheduledThreadPool
创建一个线程数量固定的线程池,可以定时或者周期性执行任务。使用继承ExecutorService的ScheduledExecutorService类。
1)、schedule,延迟执行。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 2, TimeUnit.SECONDS);//延时2秒执行
}
scheduledThreadPool.shutdown();
System.out.println("main执行完成");
}
}
运行结果:
main执行完成
pool-1-thread-3正在执行,num = 2,延时:2002ms
pool-1-thread-1正在执行,num = 0,延时:2001ms
pool-1-thread-2正在执行,num = 1,延时:2002ms
2)、scheduleAtFixedRate,延时定时执行,上一个任务开始执行的时间 + 周期时间 = 下一个任务的开始时间。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(300);//线程休眠300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 1, 2, TimeUnit.SECONDS);//延时2秒执行
}
}
}
运行结果:
pool-1-thread-1正在执行,num = 0,延时:1305ms
pool-1-thread-3正在执行,num = 2,延时:1302ms
pool-1-thread-2正在执行,num = 1,延时:1303ms
pool-1-thread-2正在执行,num = 1,延时:3303ms
pool-1-thread-1正在执行,num = 2,延时:3302ms
pool-1-thread-3正在执行,num = 0,延时:3304ms
3)、 scheduleWithFixedDelay,延时定时执行,上一个任务结束时间 + 周期时间 = 下一个任务的开始时间。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(300);//线程休眠300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 1, 2, TimeUnit.SECONDS);//延时2秒执行
}
}
}
运行结果:
pool-1-thread-1正在执行,num = 0,延时:1304ms
pool-1-thread-3正在执行,num = 2,延时:1301ms
pool-1-thread-2正在执行,num = 1,延时:1301ms
pool-1-thread-2正在执行,num = 2,延时:3604ms
pool-1-thread-3正在执行,num = 0,延时:3607ms
pool-1-thread-1正在执行,num = 1,延时:3604ms
5、newSingleThreadScheduledExecutor
创建单线程的线程池,可以定时或者周期性执行任务。与4中的区别是它是单线程。
1)、schedule,延时执行
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
singleThreadScheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 2, TimeUnit.SECONDS);//延时2秒执行
}
singleThreadScheduledThreadPool.shutdown();
System.out.println("main执行完成");
}
}
运行结果:
main执行完成
pool-1-thread-1正在执行,num = 0,延时:2002ms
pool-1-thread-1正在执行,num = 1,延时:2000ms
pool-1-thread-1正在执行,num = 2,延时:2000ms
2)、scheduleAtFixedRate,延时定时执行,上一个任务开始执行的时间 + 周期时间 = 下一个任务的开始时间。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
singleThreadScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(300);//线程休眠300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 1, 2, TimeUnit.SECONDS);//延时1秒,每2秒执行一次
}
}
}
运行结果:
pool-1-thread-1正在执行,num = 0,延时:1302ms
pool-1-thread-1正在执行,num = 1,延时:1603ms
pool-1-thread-1正在执行,num = 2,延时:1905ms
pool-1-thread-1正在执行,num = 0,延时:3303ms
pool-1-thread-1正在执行,num = 1,延时:3603ms
pool-1-thread-1正在执行,num = 2,延时:3904ms
3)、scheduleWithFixedDelay,延时定时执行,上一个任务结束时间 + 周期时间 = 下一个任务的开始时间。
package com.su.mybatis.oracle.controller;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
for(int i = 0;i<3;i++){
final int num = i;
final long time1 = System.currentTimeMillis();
singleThreadScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(300);//线程休眠300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
+ ",延时:" + (System.currentTimeMillis()-time1) + "ms");
}
}, 1, 2, TimeUnit.SECONDS);//延时1秒,每2秒执行一次
}
}
}
运行结果:
pool-1-thread-1正在执行,num = 0,延时:1304ms
pool-1-thread-1正在执行,num = 1,延时:1602ms
pool-1-thread-1正在执行,num = 2,延时:1902ms
pool-1-thread-1正在执行,num = 0,延时:3607ms
pool-1-thread-1正在执行,num = 1,延时:3905ms
pool-1-thread-1正在执行,num = 2,延时:4205ms
以上就是常用线程池的使用方法,根据不同场景使用不同的线程池。
如果有写的不对的地方,请大家多多批评指正,非常感谢!