标签:
demo,请用intellij idea 打开,或者用文本编辑查看代码
线程池作用就是限制系统中执行线程的数量。 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费系统资源,多了造成系统拥挤效率不高。
当一个新任务需要运行时,如果线程 池中有等待的工作线程,就可以开始运行了;否则进入等待队列。 为什么要用线程池: 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性 能。因为线程的生成关闭很浪费资源 所以不要频繁的创建新线程而是使用线程池。
线程池就是管理线程的地方, 不用了线程池可以让它休眠 而且比你管理的要好的多。线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调 整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
Executor详解: Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。ThreadPoolExecutor是Executors类的底层实现。我们先介绍下Executors。 Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要。
有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类,熟悉这部分API特征是一项艰难的学习过程。目前有关这方面的资料和书籍都少之又少,大所属介绍线程方面书籍还停留在java5之前的知识层面上。
当然新特征对做多线程程序没有必须的关系,在java5之前通用可以写出很优秀的多线程程序。只是代价不一样而已。
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
在Java5之前,要实现一个线程池是相当有难度的,现在Java5为我们做好了一切,我们只需要按照提供的API来使用,即可享受线程池带来的极大便利。
Java5的线程池分好多种:固定尺寸的线程池、可变尺寸连接池。
在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建线程池的静态方法,是必须掌握的。 实
Java代码
xxxxxxxxxx
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
?
for (int i = 1; i <= 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("zxy, 线程:"+threadName+",正在执行第" + index + "个任务");
try {
Random random = new Random(System.currentTimeMillis());
int r = random.nextInt(3) + 1;
Thread.sleep(r*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
第一行代码,创建了一个包含3个线程的线程池。下面的代码是用来测试这个线程池是如何工作的,for循环共创建了10个任务,每个任务所需时间不等。由于线程池中只有3个线程,所以从第四个任务就需要等待前面有任务被执行完,有空余线程的时候才能开始。
在上例的基础上改一行创建pool对象的代码为:
//创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 Java代码
xxxxxxxxxx
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
//下面的测试代码和上面的相同
对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。
一旦池中有线程完毕,则排队等待的某个线程会入池执行。
与上面的类似,只是改动下pool的创建方式:
//创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 Java代码
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
Java代码
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); //延迟2秒后执行该任务 scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("我是两秒后执行的那个线程"); } }, 2, TimeUnit.SECONDS); //延迟1秒后,每隔2秒执行一次该任务 scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("我是一秒后执行的那个线程,注意每隔两秒我会出现一次"); } }, 1, 2, TimeUnit.SECONDS);
在四代码基础上,做改动
//创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
Java代码
xxxxxxxxxx
ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();
//延迟1秒后,每隔2秒执行一次该任务
singleThreadScheduledPool.scheduleAtFixedRate(new Runnable() {
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("zxy, 线程:" + threadName + ",正在执行");
}
},1,2, TimeUnit.SECONDS);
Java代码
xxxxxxxxxx
BlockingQueue bqueue = new ArrayBlockingQueue(20);
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2, TimeUnit.MILLISECONDS,bqueue); //创建一个核心线程数为2,最多为3,多余核心线程数的线程的存活时间为2毫秒,创建的线程放到bqueue队列中
?
for (int i = 1; i <= 10; i++) {
final int index = i;
pool.execute(new Runnable() {
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("zxy, 线程:"+threadName+",正在执行第" + index + "个任务");
try {
Random random = new Random(System.currentTimeMillis());
int r = random.nextInt(3) + 1;
Thread.sleep(r*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
标签:
原文地址:http://www.cnblogs.com/waj6701/p/5654032.html