在劫

吾生也有涯,而知也无涯 。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

线程池的作用:
1、减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务;
2、可以根据系统的承受能力,调整线程池中工作线程的数据,防止因为消耗过多的内存导致服务器奔溃。
使用线程池,要根据系统的环境情况,手动或自动设置线程数目。少了系统运行效率不高,多了系统拥挤、占用内存多。用线程池控制数量,其他线程排队等候。一个任务执行完毕,再从队列中取最前面的任务开始执行。若任务重没有等待任务,线程池浙一资源处于等待。当一个新任务需要运行,如果线程池中有等待的工作线程,就可以开始运行,否则进入等待队列。
ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 
    ThreadFactory threadFactory, RejectedExecutionHandler handler)

ThreadPoolExecutor类的另外三个构造器都是调用上面这个构造器进行初始化工作的。
int corePoolSize:核心池的大小。创建线程池后,默认情况下,线程池中没有任何线程,而是等待有任务到来才创建线程去执行任务。默认情况下,在创建线程池后,线程池钟的线程数为0,当有任务到来后就会创建一个线程去执行任务。
maximumPoolSize:池中允许的最大线程数,这个参数表示了线程池中最多能创建的线程数量,当任务数量比corePoolSize大时,任务添加到workQueue,当workQueue满了,将继续创建线程以处理任务,maxmumPoolSize表示的就是workQueue满了,线程池中最多可以创建的线程数量。
keepAliveTime:表示线程没有任务执行时最多保持多久时间终止。默认情况下,只有当线程池中的数量大于corePoolSize时,才会起作用,直到线程池中的线程数不大于corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0。
unit:参数keepAliveTime的时间单位,有七种取值:

TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLSECONDS; //毫秒
TimeOut.MICROSECONDS; //微秒
TimeOut.NANOSECONDS; //纳秒

workQueue:一个阻塞队列,用来存储等待执行的任务。一般来说,这里的阻塞队列有一下几个选择:

ArrayBlockingQueue; //基于数组的先进先出队列,此队列创建时必须指定大小
LinkedBlockingQueue; //基于链表的先进先出队列,如果没有指定队列大小,默认Integer.MAX_VALUE
SynchronousQueue; //不会保存提交的任务,直接创建一个线程来执行新来的任务
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关

ThreadFactory:线程工厂,主要用来创建线程

class SimpleThreadFactory implements ThreadFactory {
   public Thread newThread(Runnable r) {
     return new Thread(r);
   }

handler:当拒绝处理任务时的策略,有四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常(默认这种拒绝策略)。 
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

Executor
线程池的重点不是类怎么用,而是在合适的场景下使用合适的线程池,所谓合适的线程池就是ThreadPoolExecutor的构造方法传入不同的参数,构造出不同的线程池,以满足实际需求。
单线程线程池:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

示例:

//单线程线程池
/*	核心池大小--1 线程池容量--1 workqueue--LinkedBlockingQueue
 *     public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
 */
public class ThreadPoolExectorJava {
	public static void main(String[] args) {
		//注意:这里返回的是ExecutorService接口,不是ThreadPoolExecutor
		//从Executors得到的是ExecutorService或ScheduledExecutorService接口,而不是这两个接口的实现类
		ExecutorService tpe = Executors.newSingleThreadExecutor();
		tpe.execute(new ThreadPoolRunnable());
	}
}

单线程线程池运行的线程数是1,选择无界的LinkedBlockingQueue。不管传入多少任务都排序,前面一个任务执行完毕,再执行队列中的线程。这里第二个参数maximumPoolSize是没有意义的,因为maximumPoolSize描述的排队的任务多过workQueue的容量,线程池中对多只能容纳maximumPoolSize个任务,现在workQueue是无界的,也就是说排队的任务永远不会多过workQueue的容量,maximumPoolSize设置成多少都没有意义。
固定大小线程池:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

程序示例:

//固定大小线程池
public class ThreadPoolExectorJava {
	public static void main(String[] args) {
		ExecutorService tpe = Executors.newFixedThreadPool(3);
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
	}
}

固定大小的线程池和单线程的线程池差不多,无非是让线程池中能运行的线程手动制定了nThread。选择的LinkedBlockingQueue,所以maximumPoolSize是无意义的
无界线程池:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

程序示例:

//无界线程池
public class ThreadPoolExectorJava {
	public static void main(String[] args) {
		ExecutorService tpe = Executors.newCachedThreadPool();
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());
	}
}

无界线程池,就是不管多少任务提交进行,都直接运行。无界线程池采用SynchronousQueue,采用这个线程池就没有workQueue容量一说了,只要添加进去的线程就会被拿去用。无界线程池的线程数是没有上限的,所以以maximumPoolSize为主了,设置为一个近似无限大的Integer.MAX_VALUE。另,单线程线程池和固定大小线程池线程是不会自动回收的,也即是说保证提交进来的任务最后会被处理,但不保证什么时候处理。无界线程池是设置了回收时间的,由于corePoolSize为0,所以只要60秒没有被用到的线程都会被直接移除。
workQueue:
  workQueue就是排队策略。排队策略描述的是当前线程大于corePoolSize时,线程以什么样的方式等待被运行。
  排队有三种策略:直接提交、有界队列、无界队列。JDK使用了无界队列LinkedBlockingQueue作为workQueue而不是有界队列ArrayBlockingQueue,尽管后者可以对资源进行控制,但是有界队列相比无界队列有三个缺点:
  1、使用有界队列,corePoolSize、maximumPoolSize两个参数势必要根据实际场景不断调整以求达到一个最佳,这会给开发带来极大的麻烦,必须经过大量的性能测试。所以干脆用无界,永远添加到队列中,不会溢出,自然maximumPoolSize就没啥用了,只需要根据系统处理能出调整corePoolSize就可以;
  2、放置业务突刺,尤其是在Web应用中,某些时候突然大量请求的到来。使用无界队列,不管什么时候,至少保证所有任务能够被处理,有界的超过maximumPoolSize的任务就可能被丢弃掉。
  3、有界队列大小和maximumPoolSize也需要相互折中,这又是一个难搞的地方。
线程池容量的动态调整

setCorePoolSize:设置核心池大小
setMaximumPoolSize:设置线程池最大能创建的线程数目大小

线程池的关闭

shutdown(): 不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但不再接受新任务
shutdownNow(): 立即终止线程池,并尝试打算正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务


线程工厂接口ThreadFactory

import java.util.concurrent.ThreadFactory;

public class ThreadFactorJava {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//工厂类对象
		MyThreadFactory mtf = new MyThreadFactory();
		//线程类对象
		FactoryRunnable tpr = new FactoryRunnable();
		//创建线程
		Thread t = mtf.newThread(tpr);
		t.setName("线程一");
		Thread t2 = mtf.newThread(tpr);
		t2.setName("线程二");
		//执行线程
		t.start();
		t2.start();
	}

}
//创建类实现接口
class MyThreadFactory implements ThreadFactory{	
	public Thread newThread(Runnable r) {
		int i = 0;
		Thread  t = new Thread(r, "线程工厂创建" );
		return t;
	}	
}

//线程类
class FactoryRunnable implements Runnable{

	@Override
	public void run() {
		while(true) {
			System.out.println(Thread.currentThread().getName() + "执行");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
}

线程池的使用

public class ThreadPoolRunnable implements Runnable{
	private static int i= 20;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			if(i > 0) {
				System.out.println(Thread.currentThread().getName() + "------" +(i--));
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}

public class ThreadPoolExectorJava {
	public static void main(String[] args) {
		//SynchronousQueue
		BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
		ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 2, 60L, TimeUnit.SECONDS, workQueue);
		tpe.execute(new ThreadPoolRunnable());
		tpe.execute(new ThreadPoolRunnable());

	}
}

自定义线程池

package newJava.newRunnable;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExectorJava {
	public static void main(String[] args) {
		// 注意:最大线程数 >= worjQueue + 核心线程数
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(3);
		ThreadPoolFactor tpf = new ThreadPoolFactor();
		// ThreadPoolFactor tpf = Executors.defaultThreadFactory();
		// 当线程装满等待列表,抛出异常
		// ThreadPoolExecutor.AbortPolicy handler = new
		// ThreadPoolExecutor.AbortPolicy();
		// 不抛出异常
		// RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
		RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
		ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, workQueue, tpf, handler);
		ThreadPoolRunnable tpr = new ThreadPoolRunnable();
		ThreadPoolRunnable2 tpr2 = new ThreadPoolRunnable2();
		// 设置了等待列表装满就抛出异常,这里会抛出异常
		// for(int i = 0; i < 10; i++) {
		// tpe.execute(tpf.newThread(tpr));
		// }
		// 这里不会抛出异常
		tpe.execute(tpf.newThread(tpr));
		tpe.execute(tpf.newThread(tpr));
		tpe.execute(tpf.newThread(tpr));
		tpe.execute(tpf.newThread(tpr));
		tpe.execute(tpf.newThread(tpr2));
		tpe.execute(tpf.newThread(tpr2));
		tpe.execute(tpf.newThread(tpr2));
		tpe.execute(tpf.newThread(tpr2));
		tpe.execute(tpf.newThread(tpr2));
		// 关闭线程
		tpe.shutdown();
	}
}

class ThreadPoolRunnable2 implements Runnable {
	private int i = 0;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		b: while (true) {
			if (i < 5) {
				System.out.println("ThreadPoolRunnable2正在执行--------" + Thread.currentThread().getName());
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				break b;
			}
		}

	}

}

posted on 2018-07-16 03:04  长嘴大耳怪  阅读(122)  评论(0编辑  收藏  举报