我们平时在敲代码中常用多线程来提高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();
}
}
运行效果:
以上四中线程池分别运用于不同场景,可在项目中依据实际情况选择应用。线程池的作用不不过可控制创建线程的数量,很多其它的是在多线程中省去了频繁的线程创建和销毁过程,减少了系统销毁。