我们平时在写程序中常常使用多线程来提高CPU以及其他资源的利用率,但是当CPU中的线程超过了CPU调度范围时,我们的程序就会变得缓慢甚至出现死锁导致程序卡死等现象。也有很多时候我们需要创建的线程量巨大,但是每个线程的执行时间却相对较小,这样在新启线程和关闭线程的时候消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。
线程池的出现能较好的解决以上问题,线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供了四种比较常用线程池。
MyThread类代码
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
}
}
1.newCachedThreadPool
newCachedThreadPool() 是根据需求创建新线程的,需求多时,创建的就多,需求少时,JVM自己会慢慢的释放掉多余的线程,它是一种可变尺寸的线程池。
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
cachedThreadPool.execute(t1);
cachedThreadPool.execute(t2);
cachedThreadPool.execute(t3);
cachedThreadPool.execute(t4);
cachedThreadPool.execute(t5);
// 关闭线程池
cachedThreadPool.shutdown();
}
}
运行效果:
2.newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。新的线程加入后,如果正在运行的线程达到了上限,则会阻塞,直到有了空闲的线程来运行。他是定长尺寸的线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPool {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
fixedThreadPool.execute(t1);
fixedThreadPool.execute(t2);
fixedThreadPool.execute(t3);
fixedThreadPool.execute(t4);
fixedThreadPool.execute(t5);
// 关闭线程池
fixedThreadPool.shutdown();
}
}
此时线程池的最大线程为3,运行效果:
3.newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThredPool {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
// 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
// 将线程放入池中进行执行
scheduledThreadPool.execute(t1);
// 使用延迟执行风格的方法
scheduledThreadPool.schedule(t2, 1000, TimeUnit.MILLISECONDS);
scheduledThreadPool.schedule(t3, 10, TimeUnit.MILLISECONDS);
// 关闭线程池
scheduledThreadPool.shutdown();
}
}
运行效果(延迟过程需要自己实践):
4.newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutor {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
singleThreadExecutor.execute(t1);
singleThreadExecutor.execute(t2);
singleThreadExecutor.execute(t3);
singleThreadExecutor.execute(t4);
singleThreadExecutor.execute(t5);
// 关闭线程池
singleThreadExecutor.shutdown();
}
}
运行效果:
以上四中线程池分别运用于不同场景,可在项目中根据实际情况选择应用,线程池的作用不仅仅是可控制创建线程的数量,更多的是在多线程中省去了频繁的线程创建和销毁过程,降低了系统销毁。