学习整理——Java线程池

线程VS线程池

为什么要使用线程池?我们知道,在Java创建并运行一个线程很简单,只需要实现run()方法并在合适时间点上调用start()方法即可。但是无法在表面看到的是,Java的Thread类调用native方法创建并运行一个线程需要多大的开销。如果在程序中需要有大量的线程执行,对于每一个线程都调用native去创建并运行,势必会造成很大的资源消耗,更多的计算资源集中在创建、开始、销毁线程的工作上,而这时线程池的出现可以解决这方面的问题。所谓线程池就是事先在一个池里创建多个线程并执行它们,即使是空任务它们也可以在循环里跑。一旦外部有线程的执行需求,可以将该需求丢进池里,让其中的正在执行的线程去调用执行,而不是为该需求重新创建线程,节省系统开销。


使用线程池需要注意

1.线程池的大小:该大小决定着同一时间可以执行的任务数。如果太小的话,工作线程可能无法适应任务需求的速度,造成后进的线程需要等待较长时间;太大的话,会浪费内存和计算资源,因为工作线程在无任务的情况下依然会占用CPU时间,接受调度;

2.关闭线程池:使用完线程池需要执行关闭,不然执行完所有任务之后依然会占用CPU时间和内存;


代码

基于以上的初等认识,可以实现自己的线程池,当然需要改进和补充的地方还有很多。

线程池的更多介绍可以参考:传送门1  传送门2

import java.util.LinkedList;
import java.util.List;

public class MyThreadPool {
	private int poolSize;             // 核心池大小
	private MyConcreteThread[] concreteThread;             //  工作线程
	private List<Runnable> threadList = new LinkedList<Runnable>();   // 任务队列
	
	
	private static MyThreadPool threadPool = null;   //  单例模式
	private MyThreadPool(){
		this(5);                      //  默认大小
	}
	private MyThreadPool(int poolSize){
		this.poolSize = poolSize;
		concreteThread = new MyConcreteThread[poolSize];
		for(MyConcreteThread oneThread:concreteThread){
			oneThread = new MyConcreteThread();
			oneThread.start();                // 启动线程
		}
	}
	
	public static MyThreadPool getInstance(){
		if(threadPool == null){
			synchronized (MyThreadPool.class) {
				if(threadPool == null)
					threadPool = new MyThreadPool();
			}
		}
		return threadPool;
	}
	
	public static MyThreadPool getInstance(int poolSize){
		if(threadPool == null){
			synchronized (threadPool) {
				if(threadPool == null)
					threadPool = new MyThreadPool(poolSize);
			}
		}
		return threadPool;
	}
	
	//  添加单个线程
	public void execute(Runnable r){
		synchronized (threadList) {
			threadList.add(r);
			threadList.notify();
		}
	}
	
	//  批量添加线程
	public void execute(Runnable[] rs){
		synchronized (threadList) {
			for(Runnable r:rs)
				threadList.add(r);
			threadList.notify();
		}
	}
	
	//  获取线程池大小
	public int getPoolSize(){
		return poolSize;
	}
	
	// 工作线程,内部类
	class MyConcreteThread extends Thread{
		@Override
		public void run(){
			while(!isInterrupted()){
				Runnable r = null;
				synchronized (threadList) {
					while(threadList.isEmpty()){
						try{
							threadList.wait();        //  该线程没有工作,让出队列对象
						}catch(InterruptedException e){
							e.printStackTrace();
						}
					}
					if(!threadList.isEmpty())
						r = threadList.remove(0);    //取出第一个
				}
				if(r != null){
					r.run();               // 在工作线程里调用run方法,相当于执行了该线程
				}
				r = null;
			}
		}
	}
}

运行测试

单个添加

public class TestThreadPool {
	public static void main(String arg[]){
		Runnable r1 = new Runnable() {
			
			public void run() {
				System.out.println("Thread 1 run!");
			}
		};
		Runnable r2 = new Runnable() {
			
			public void run() {
				System.out.println("Thread 2 run!");
			}
		};
		
		MyThreadPool myThreadPool = MyThreadPool.getInstance();
		myThreadPool.execute(r1);
		myThreadPool.execute(r2);
		
		try{
			Thread.sleep(1000);
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("Main thread end!");
	}
}
结果

Thread 2 run!
Thread 1 run!
Main thread end!

Thread 1 run!
Thread 2 run!
Main thread end!


批量添加

public class TestThreadPool {
	
	public static void main(String arg[]){
		MyThreadPool myThreadPool = MyThreadPool.getInstance();
		TestThread[] tests = new TestThread[10];
		for(int i=0;i<10;i++){
			tests[i] = new TestThread(i);
		}
		
		myThreadPool.execute(tests);
		
		try{
			Thread.sleep(1000);
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("Main thread end!");
	}
}

class TestThread extends Thread{
	private int number;
	public TestThread(int number){
		this.number = number;
	}
	@Override
	public void run(){
		System.out.println("Thread "+ number + " run!");
	}
	
}
运行

Thread 0 run!
Thread 1 run!
Thread 2 run!
Thread 3 run!
Thread 4 run!
Thread 5 run!
Thread 6 run!
Thread 7 run!
Thread 8 run!
Thread 9 run!
Main thread end!


jdk线程池

jdk已经为我们封装好了线程池,应用时可以放心使用,以下简单叙述下关于线程池的类。

Executor接口

线程池类都实现了该接口,该接口提供一个方法execute(),该方法接受一个Runnable类型的参数,表面上是执行该任务,实际上是将其提交到线程池中。


ExecutorService接口

继承Executor,在Executor的基础上多提供了几个接口。


ThreadPoolExecutor类

用户自定义配置的线程池类,实例出来即可以用。


Executor类

实现了ExecutorService。对于用户而言,有时候并不需要自己去配置线程池,该类则事先为我们创建好一个优秀的线程池,现在只需要去获取即可。

该类提供了几种配置的线程池,分别使用以下方法返回:

newCacheThreadPool():在有任务时才创建新线程,空闲线程被保留60秒;

newFixedThreadPool(int nThreads):线程池中包含固定数目的线程,空闲线程被一直保留。参数是设置线程的数目;

newSingleThreadExecutor():线程池中只有一个工作线程,该线程会依次执行任务;

newScheduledThreadPool(int corePoolSize):线程池能按时间计划执行任务,允许用户设定计划执行任务的时间。参数corePoolSize设定工作线程的最小数目,如果任务较多,线程池可以动态增加工作线程;

newSingleThreadScheduledExecutor():线程池只有一个工作线程,并能够按时间计划来执行任务。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值