线程池的底层实现和5种创建方式

         JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发应用程序。主要包含原子量、并发集合、同步器、可重入锁,并对线程池的构造提供

了强力的支持。

线程池的各个参数的意义及实现见贴线程、线程池

                                                         线程池的实现原理

           线程池的5中创建方式

 

1、  SingleThreadExecutor : 只有一个线程的线程池,因此所有提交的任务是顺序执行

代码: Executors.newSingleThreadExecutor()

 

2、  Cached Thread Pool : 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,如果线程超过60秒内没执行,那么将被终止并从池中删除

代码:Executors.newCachedThreadPool()

 

3、  FixedThread Pool: 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,

代码: Executors.newFixedThreadPool(4)

在构造函数中的参数4是线程池的大小,你可以随意设置,也可以和cpu的数量保持一致,获取cpu的数量int cpuNums =Runtime.getRuntime().availableProcessors();

 

4、  ScheduledThreadPool : 用来调度即将执行的任务的线程池,

代码:Executors.newScheduledThreadPool()

 

5、  SingleThread Scheduled Pool : 只有一个线程,用来调度执行将来的任务,代码:Executors.newSingleThreadScheduledExecutor()

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
 * 列出并发包中的各种线程池
 * @author
 *
 */
public class ExecutorDemo {
	
	public static void main(String[] args) {
		ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
		ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
		
		int cpuNums = Runtime.getRuntime().availableProcessors();
		System.out.println(cpuNums);
		ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(cpuNums);
		ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(8);
		
		
		ScheduledExecutorService newSingleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
	}
}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.sun.corba.se.impl.encoding.OSFCodeSetRegistry.Entry;

public class TestPool {

	public static void main(String[] args) throws Exception {
		Future submit = null;
		Random random = new Random();
		
		//创建固定数量线程池
//		ExecutorService exec = Executors.newFixedThreadPool(4);
		
		//创建调度线程池
		ScheduledExecutorService exec = Executors.newScheduledThreadPool(4);
		
		//用来记录各线程的返回结果
		ArrayList> results = new ArrayList>();
		
		for (int i = 0; i < 10; i++) {
			//fixedPool提交线程,runnable无返回值,callable有返回值
			/*submit = exec.submit(new TaskRunnable(i));*/
			/*submit = exec.submit(new TaskCallable(i));*/
			
			//对于schedulerPool来说,调用submit提交任务时,跟普通pool效果一致
			/*submit = exec.submit(new TaskCallable(i));*/
			//对于schedulerPool来说,调用schedule提交任务时,则可按延迟,按间隔时长来调度线程的运行
			submit = exec.schedule(new TaskCallable(i), random.nextInt(10), TimeUnit.SECONDS);
			//存储线程执行结果
			results.add(submit);
			
		}
		
		
		//打印结果
		for(Future f: results){
			boolean done = f.isDone();
			System.out.println(done?"已完成":"未完成");  //从结果的打印顺序可以看到,即使未完成,也会阻塞等待
			System.out.println("线程返回future结果: " + f.get());
		}
		
		exec.shutdown();
		
	}
}


²  线程池的使用

 

提交Runnable ,任务完成后Future 对象返回 null

见代码:ThreadPoolWithRunable

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolWithRunable {

	
	/**
	 * 通过线程池执行线程
	 * @param args
	 */
	public static void main(String[] args) {
		//创建一个线程池
		ExecutorService pool = Executors.newCachedThreadPool();
		for(int i = 1; i < 5; i++){
			pool.execute(new Runnable() {
				@Override
				public void run() {
					System.out.println("thread name: " + Thread.currentThread().getName());
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		pool.shutdown();
	}

}

提交 Callable该方法返回一个 Future实例表示任务的状态

见代码:ThreadPoolWithcallable

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * callable 跟runnable的区别:
 * runnable的run方法不会有任何返回结果,所以主线程无法获得任务线程的返回值
 * 
 * callable的call方法可以返回结果,但是主线程在获取时是被阻塞,需要等待任务线程返回才能拿到结果
 * @author
 *
 */
public class ThreadPoolWithcallable {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService pool = Executors.newFixedThreadPool(4); 
		
		for(int i = 0; i < 10; i++){
			Future submit = pool.submit(new Callable(){
				@Override
				public String call() throws Exception {
					//System.out.println("a");
					Thread.sleep(5000);
					return "b--"+Thread.currentThread().getName();
				}			   
			   });
			//从Future中get结果,这个方法是会被阻塞的,一直要等到线程任务返回结果
			System.out.println(submit.get());
		} 
			pool.shutdown();

	}

}


.1.     java并发包消息队列及在开源软件中的应用

BlockingQueue也是java.util.concurrent下的主要用来控制线程同步的工具。

主要的方法是:puttake一对阻塞存取addpoll一对非阻塞存取。

         插入:

        1)add(anObject):把anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则抛出

        2)offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.

        3)put(anObject):anObject加到BlockingQueue,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.

         读取:

        4)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null

        5)take():取走BlockingQueue里排在首位的对象,BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止

         其他

intremainingCapacity();返回队列剩余的容量,在队列插入和获取的时候,不要瞎搞,数  据可能不准

booleanremove(Object o); 从队列移除元素,如果存在,即移除一个或者更多,队列改   变了返回true

publicboolean contains(Object o); 查看队列是否存在这个元素,存在返回true

intdrainTo(Collection c); 传入的集合中的元素,如果在队列中存在,那么将    队列中的元素移动到集合中

intdrainTo(Collection c, int maxElements); 和上面方法的区别在于,制定了移   动的数量

 

BlockingQueue有四个具体的实现类,常用的两种实现类为:

 

1、ArrayBlockingQueue个由数组支持的有界阻塞队列,规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的。

 

2、LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的。

         LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到puttake方法put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来

 

LinkedBlockingQueue和ArrayBlockingQueue区别:

LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue数据吞吐量要大ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue.

 

生产者消费者的示例代码:

见代码

你可能感兴趣的:(Java高级)