Java线程池的认识、常用线程池的分析

什么是程序,什么是进程,什么是线程,他们有什么区别?

程序是指令和数据的有序集合,其本身并没有任何运行的含义,是一个静态的概念。

进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序得到运行就可以看作是一个进程。进程可以包含多个同时运行的线程。进程也是拥有系统资源分配的最小基本单位。

线程是进程的实体,是CPU调度和分派的最小基本单位,是比线程更小的能独立运行的基本单位。一个进程至少有一个线程。那有时候简单的一个小程序并没有用到线程,线程又从何而来?这里的线程是由CPU调用资源时产生的线程,就是我们常说的主线程(姑且理解成主函数那个代码块吧!)。线程类创建线程只是给了我们一个调度资源的机会,而不是说线程必须是我们创建,只要需要CPU调度资源就需要线程的创建,我们不创建,JVM自己创建(通常情况下就是这个主线程了)。

更深刻的了解可以看这里,比喻生动形象https://www.cnblogs.com/dreamroute/p/5207813.html

什么是线程池?

顾名思义,就是事先创建若干个可执行的线程放进一个“池(容器)”里面,需要的时候就直接从池里面取出来不需要自己创建,使用完毕也不需要销毁而是放进“池”中,从而减少了创建和销毁对象所产生的开销。

为什么使用(线程)池?

在面向对象的编程中,创建和销毁对象非常耗费时间,因为创建一个对象需要获得内存资源或者其他更多的资源。在Java中更是如此,虚拟机甚至试图跟踪每个对象,以便能够在对象销毁后进行垃圾回收。所以,提高效率的一个手段就是尽可能减少对象创建和销毁的次数,这就是“池化资源”技术产生的原因。所以,将线程资源准备好放在一个池里面提高效率呀!

扫描二维码关注公众号,回复: 4023330 查看本文章

   

线程池的使用

ExecutorService:线程池接口

ExecutorService  pool(池名称)  =  Executors.常用线程池名;

例:

​
ExecutorService pool = Executors.newSingleThreadExecutor();

线程池(前四种常用吧)

  • newsingleThreadExecutor

单个线程的线程池,即线程池中每次只有一个线程在工作,单线程串行执行任务

public class single {

	public static void main(String[] args) {
		//创建池
		ExecutorService pool = Executors.newSingleThreadExecutor();
		
		for(int i = 0;i<5;i++) {
			int number = i;
			//一个新线程加入池
			pool.execute(new Runnable() {
				
				@Override
				public void run() {
					System.out.println("现在时间是:"+System.currentTimeMillis()+"第"+number+"个线程");
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		//关闭池
		pool.shutdown();
	}

}

看输出在设置的时间段里每次只有一个线程执行 ,按顺序执行 

  • newfixedThreadExecutor(n)

固定数量的线程池,每提交一个任务就是一个线程,直到达到线程池的最大数量,然后在后面等待队列前面的线程执行或者销毁

public class fixed {
	public static void main(String[] args) {
		
		//创建池,可放置4个线程
		ExecutorService pool = Executors.newFixedThreadPool(4);
		
		for(int i = 0;i<7;i++) {
			int number = i;
			//将线程加入池
			pool.execute(new Runnable() {
				
				@Override
				public void run() {
					System.out.println("现在时间是:"+System.currentTimeMillis()+"第"+number+"个线程"+Thread.currentThread().getName());
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
	}
}

 

此时执行并不是有序的,抢资源  

  • newCacheThreadExecutor

一个可缓存的线程池。当线程池超过了处理任务所需要的线程数,那么就会回收部分闲置线程(一般是闲置60s)。当有任务来时而线程不够时,线程池又会创建新的线程,当线程够时就调用池中线程。适用于大量的耗时较少的线程任务。

可能导致内存溢出,一般使用newFixedThreadPool代替 

public class cache {

	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			int number = i;
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			pool.execute(new Runnable() {
				@Override
				public void run() {
					System.out.println(
						System.currentTimeMillis() + "第" + number + "个线程" + Thread.currentThread().getName());
				}
			});
		}
	}

}

此时一直只有一个线程执行,因为每个时间段内总有闲置的线程。

            /**
             * Thread.sleep写在线程里面的时候,只是让线程在运行的过程中休眠2s,并没有运行后休眠2s
             * 如果Thread.sleep写在run方法里面,for循环中依旧没有闲置的线程,会创新的线程
             */

 

  • newScheduleThreadExecutor

一个大小无限的线程池,但是核心线程数量是固定的,非核心线程无限制,并且非核心线程一旦闲置立刻回收。此线程池支持定时以及周期性执行任务的需求,即该线程池可给定延迟执行的命令或者定时执行命令。该线程池多用于执行延迟任务或者固定周期的任务。

public class schedule {

	public static void main(String[] args) {
		//设置池中核心线程数量2
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
		System.out.println("现在时间"+System.currentTimeMillis());

        /**
		 * pool.schedule(callable, delay, unit)
		 * callable - 要执行的功能
			delay - 从现在开始延迟执行的时间
			unit - 延迟参数的时间单位
		 */
		pool.schedule(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("现在时间"+System.currentTimeMillis());
				
			}
		}, 4, TimeUnit.SECONDS);//设置延迟4s执行
}
}

  • newSingleThreadScheduledExecutor 

创建只有一条线程的线程池,他可以在指定延迟后执行线程任务

  • newWorkStealingPool 

会更加所需的并行层次来动态创建和关闭线程。它同样会试图减少任务队列的大小,所以比较适于高负载的环境。同样也比较适用于当执行的任务会创建更多任务,如递归任务

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/82867087