黑马程序员-Java多线程之线程池初学

来源:互联网 发布:windows 2008配置域名 编辑:程序博客网 时间:2024/05/16 03:53
------- android培训、java培训、期待与您交流! ----------

    线程池是一种多线程处理形式,负责管理工作线程,包含一个等待执行的任务队列。线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象。

      线程池的作用就是用来线程池作用就是限制系统中执行线程的数量,传统的多线程中不使用线程池技术,每个线程完成自己的任务之后就会销毁,得不到复用,每个线程的创建和销毁是很消耗系统资源的,如果线程能够得到复用,则解决了此问题。在Java多线程中,我们可以自动或手动设置线程数量,达到运行的最佳效果;用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。使用线程池技术可以使多线程任务的运行效率大大提高,

      使用线程池减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务,可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而导致内存溢出,导致OutOfMemoryError原因之一就是Java栈内存溢出,由于JVM中栈空间是线程私有的,java栈的默认大小事1M,通过不断的创建新的线程可以产生内存溢出的异常,为每个线程分配的栈越大,越容易产生内存溢出。每个线程分配到的栈容量越大,可以建立的线程数量自然就越少,建立线程时就月容易把内存耗尽。抛出内存溢出异常。代码如下:

public class JavaVMStackOOM {private void dontStop() {while(true){}}/** * 不断的创建新的线程,每个线程执行一个死循环。 */public void stackLeakByThread() {while(true) {new Thread(new Runnable() {@Overridepublic void run() {dontStop();}}).start();}}/** * VM Args: -Xss2m 设置大一些,更容易造成OutofMemoryError * @param args */public static void main(String[] args) {JavaVMStackOOM oom = new JavaVMStackOOM();oom.stackLeakByThread();}}

注意:执行以上代码系统内存会耗尽,操作系统会假死,我的电脑8G内存都得强制关机,然后就悲剧了。


线程池的组成部分(Java实现):

1、线程池管理器(ThreadPoolManager):用于创建并管理线程池。--使用Executors创建线程池
       2、工作线程(WorkThread): 线程池中线程。--线程池创建的线程
       3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。--实现了Runnable接口的任务
        4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。--提交到线程池中的任务

在Java的Executors类里面提供了一些静态工厂,生成一些常用的线程池。

1. newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

2. newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

3. newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4. newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。


实例1:newSingleThreadExecutor

public class SingleThreadExecutorTest {public static void main(String[] args) {ExecutorService pool = Executors.newSingleThreadExecutor();//提交十个工作线程到线程池,线程按提交的顺序依次执行。for(int i = 1; i <= 5; i++) {final int task = i;pool.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " NO." + task +" Task is Running......");}});}pool.shutdown();}}

输出结果:

pool-1-thread-1 NO.1 Task is Running......
     pool-1-thread-1 NO.2 Task is Running......
     pool-1-thread-1 NO.3 Task is Running......
     pool-1-thread-1 NO.4 Task is Running......

pool-1-thread-1 NO.5 Task is Running......

始终都有一个线程在执行。

实例2:2. newFixedThreadPool

public class FixedThreadPoolTest {public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(3);//提交十个工作线程到线程池,一共有三个线程在执行任务。for(int i = 1; i <= 10; i++) {final int task = i;pool.execute(new Runnable() {@Overridepublic void run() {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " NO." + task +" Task is Running......");}});}pool.shutdown();}}
输出结果:

pool-1-thread-3 NO.3 Task is Running......
pool-1-thread-2 NO.2 Task is Running......
pool-1-thread-1 NO.1 Task is Running......
pool-1-thread-1 NO.6 Task is Running......
pool-1-thread-2 NO.5 Task is Running......
pool-1-thread-3 NO.4 Task is Running......
pool-1-thread-3 NO.9 Task is Running......
pool-1-thread-2 NO.8 Task is Running......
pool-1-thread-1 NO.7 Task is Running......
pool-1-thread-3 NO.10 Task is Running......
  实例3:newCachedThreadPool

public class CachedThreadPoolTest {public static void main(String[] args) {ExecutorService pool = Executors.newCachedThreadPool();//提交十个工作线程到线程池,一共创建了十个线程。for(int i = 1; i <= 10; i++) {final int task = i;pool.execute(new Runnable() {@Overridepublic void run() {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " NO." + task +" Task is Running......");}});}pool.shutdown();}}

输出结果:

pool-1-thread-2 NO.2 Task is Running......
pool-1-thread-3 NO.3 Task is Running......
pool-1-thread-1 NO.1 Task is Running......
pool-1-thread-3 NO.5 Task is Running......
pool-1-thread-2 NO.4 Task is Running......
pool-1-thread-1 NO.6 Task is Running......
pool-1-thread-1 NO.9 Task is Running......
pool-1-thread-3 NO.7 Task is Running......
pool-1-thread-2 NO.8 Task is Running......
pool-1-thread-1 NO.10 Task is Running......

实例4 newScheduledThreadPool

public class ScheduledThreadPoolTest {public static void main(String[] args) {Executors.newScheduledThreadPool(3).schedule(new Runnable() {@Overridepublic void run() {System.out.println("Ready to Running!");}}, 10, TimeUnit.SECONDS);//打印系统时间的秒,十秒后启动上面的任务while(true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Calendar.getInstance().get(Calendar.SECOND));}}}

输出结果:

51
52
53
54
55
56
57
58
59
Ready to Running!

关于线程池和java中的多线程知识还很多,在此只是做了一个简单介绍。在《Java编程思想》一书中,作者用了一百多页介绍了java的并发知识,但是作者说道这知识对并发做了一个简单介绍,学完那100多页还只算是入门级别的。所以学习之路还很长的。




ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net

0 0
原创粉丝点击