Java线程池总结

Java线程池总结

 

Java多线程知识中,线程池算是一个比较高级的知识了。但是很多面试或应用中都会有涉及到。

本文将对java线程池的知识做一下简单介绍,并用实际例子做阐述。

 




.线程池的作用:


  线程池可以很好地提高性能,尤其是当程序中需要创建大量生存周期很短的线程时,更应该考虑使用线程池。

使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能剧烈下降,

甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过此数。

 

 

 

二.线程池的创建

 

(一)静态方法

JAVA5开始新增了一个Executors工具类来产生线程池,它有如下几个静态工厂方法来创建线程池。

 

强烈建议使用较为方便的 Executors 工厂方法

1.Executors.newCachedThreadPool()  创建一个具有缓冲功能的线程池(线程池为无限大),

但是在以前构造的线程可用时将重用它们。


2.Executors.newFixedThreadPool(int) 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程


3.Executors.newSingleThreadExecutor() 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程


4.Executors.newScheduledThreadPool(int corePoolSize) 创建一个线程池,

它可安排在给定延迟后运行命令或者定期地执行


5.Executors.newSingleThreadScheduledExecutor(int corePoolSize) 创建一个只有一条线程的线程池池,

它可安排在给定延迟后运行命令或者定期地执行

 

 

上面方法中前三个方法返回的是:ExecutorService对象,

后面两个返回的是ScheduledExecutorService对象是ExecutorService的子类。


 

ExecutorService代表尽快执行线程的线程池(只要线程池中有空闲的线程,就立即执行线程任务),

程序只要将一个Runnable对象或Callable对象(代表线程任务)提交给该线程,该线程就会尽快执行该任务

 

ExecutorService方法:

shutdown() 启动一次顺序关闭线程池,执行以前提交的任务,但不接受新任务。

shutdownNow() 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表

 

 

 




(二)使用线程池来执行线程任务的步骤


1.调用Executor类的静态方法来创建一个ExecutorService对象,该对象代表一个线程池。

2.调用Runnable实现类的示例,作为线程执行任务。

3.调用ExecutorService对象的submit方法来提交Runnable示例。

4.当不想提交任务时,调用ExecutorService对象的shutdown方法来关闭线程。

 





(三)线程池的一个简单例子

 


 package com.java.ThreadPool;

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

public class PoolTest1 implements Runnable {

	public static void main(String[] args) {
		// 1.调用Executors类的静态方法来创建一个ExecutorService对象,
		ExecutorService pool = Executors.newFixedThreadPool(6);// 创建有最大运行6个线程的线程池。
		// 2.创建Runnable实现类的示例,作为线程执行任务。
		PoolTest1 p1 = new PoolTest1();
		PoolTest1 p2 = new PoolTest1();
		// 3.调用ExecutorService对象的submit方法来提交Runnable示例。
		pool.submit(p1);// 这是已经开始任务了
		pool.submit(p2);
		// 4.当不想提交任务时,调用ExecutorService对象的shutdown方法来关闭线程。
		pool.shutdown();
	}

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + " : " + i);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}



运行结果




 

这和我们普通线程的使用其实差不多,但是相关类和方法有很大的区别。

其中记住上面的四个步骤是很重要的。



 

四.下面说一下线程池的相关概述:

 

(一)什么原因使我们不得不使用线程池? 

主要原因是:短时间内需要处理的任务数量很多 



(二)使用线程池的好处

1.减少在创建和销毁线程上所花的时间以及系统资源的开销 
2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存 



(三)FixedThreadPool是一个典型且优秀的线程池,

它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。

但在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。 



(四)CachedThreadPool的特点就是在线程池空闲时,即线程池中没有可运行任务时,

它会释放工作线程,从而释放工作线程所占用的资源。但是,但当出现新任务时,

又要创建一新的工作线程,又要一定的系统开销。并且,在使用CachedThreadPool时,

一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。 




五.线程池的一个实际应用例题


题目要求:1 创建线程数量为5的线程池。 2 同时运行5个卖票窗口。 3 总票数为100,每隔一秒钟卖一张票


参考答案如下:


package com.java.test5;

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


	/**
	 * 多线程 : 1 创建线程数量为5的线程池。 2 同时运行5个卖票窗口。 3 总票数为100,每隔一秒钟卖一张票
	 * 
	 * 程序分析:
	 * 1.线程池类的使用,限制线程的个数 
	 * 2.静态变量的定义
	 * 3.代码块锁的使用
	 * */
public class ThreadTest {
	
	public static void main(String[] args) {
		 
		// 1.调用Executors类的静态方法来创建一个ExecutorService对象,该对象代表一个线程池。
		 ExecutorService pool=Executors.newFixedThreadPool(6);//创建5或5以上都可以
		 
		// 2.调用Runnable实现类的示例,作为线程执行任务。
		 //实例化站台对象,并为每一个站台取名字
		 Station station1=new Station("窗口1");
		 Station station2=new Station("窗口2");
		 Station station3=new Station("窗口3");
		 Station station4=new Station("窗口4");
		 Station station5=new Station("窗口5");
		 
		// 3.调用ExecutorService对象的submit方法来提交Runnable示例。
		 // 让每一个站台对象各自开始工作
		 pool.submit(station1);
		 pool.submit(station2);
		 pool.submit(station3);
		 pool.submit(station4);
		 pool.submit(station5);
		 
		// 4.当不想提交任务时,调用ExecutorService对象的shutdown方法来关闭线程。
		 pool.shutdown();
		 
		/*
		 *如果没有线程池,直接启动线程也能实现效果,但是效率低一点
		 *station1.start();
		 station2.start();
		 station3.start();
		 station4.start();
		 station5.start();
		 */
	}
	
	static class Station extends Thread {

		// 通过构造方法给线程名字赋值
		public Station(String name) {
			super(name);// 给线程名字赋值
		}

		// 为了保持票数的一致,票数要静态
		static int tick = 100;

		// 创建一个静态钥匙
		static Object ob = " aa";

		// 重写run方法
		@Override
		public void run() {
			while (tick > 0) {
				synchronized (ob) {// 这个很重要,必须使用一个锁,
									// 进去的人会把钥匙拿在手上,出来后才把钥匙拿出来
					if (tick > 0) {
						System.out.println(getName() + "卖出了第" + tick + "张票");
						tick--;
					} else {
						System.out.println("票卖完了");
					}
				}
				try {
					sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}



本文对java线程池作了简要的描述和使用。其中线程池还有很多相关类和方法没有说到,

想了解的可以自己多去研究。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值