Java多线程(四) 线程池

  一个优秀的软件不会随意的创建很销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互。因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理。

  JDK提供了四种不同的线程池给程序员使用  

  首先使用线程池,需要用到ExecutorService接口,该接口有个抽象类AbstractExecutorService对其进行了实现,ThreadPoolExecutor进一步对抽象类进行了实现。最后JDK封装了一个Executor类对ThreadPoolExecutor进行实例化,因此通过Executor能够创建出具有如下四种特性的线程池

  1. 无下界线程池

ExecutorService threadPool= Executors.newCachedThreadPool( ); 当线程数不足时,线程池会动态增加线程进行后续的任务调度

  2. 固定线程数的线程池

ExecutorService threadPool= Executors.newFixedThreadPool(3); 创建具有固定线程数:3个的线程池

  3. 单线程线程池

   ExecutorService threadPool= Executors.newSingleThreadScheduledExecutor( );创建单例线程池,确保线程池内恒定有1条线程在工作

  4. 调度线程池

     ScheduledExecutorService threadPool= Executors.newSingleThreadScheduledExecutor( ); 创建一个定长线程池,定时或周期性地执行任务

 1 package com.scl.thread.threadPool;
 2
 3 import java.util.concurrent.Executors;
 4 import java.util.concurrent.ScheduledExecutorService;
 5 import java.util.concurrent.TimeUnit;
 6
 7 public class ScheduledThreadPool
 8 {
 9     public static void main(String[] args)
10     {
11         // 创建定时调度线程池
12         ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
13         // 定时执行Runnable
14         threadPool.scheduleAtFixedRate(new Runnable()
15         {
16
17             @Override
18             public void run()
19             {
20                 System.out.println("do some big Scheduled");
21             }
22         }, 10, 3, TimeUnit.SECONDS);
23     }
24 }

定时调度线程池

使用线程池也比较简单,只要往线程池里面提交"任务"即可,一般使用对象.submit的方法进行,如下:

   ① threadPool.submit(Callable<T>task);

Callable跟Runnable接口一样在使用接口时会自动调用里面的call方法。与Runnable接口不一样的地方在于run方法不能返回内容,call方法含有返回参数,在外部可以通过Future 接口来接受线程返回的结果。如:Future<String> future = threadPool.submit(new MyTask( ));

② threadPool.submit(Runnable task);

由这个签名可以看出,同样地可以往线程池里面扔入Runnable接口实例。

  这如上面所说,线程池的使用就是减少程序员对线程的启动和关闭。把线程的创建及关闭交给线程池来完成。因此使用线程池来完成线程的经典问题:生产者-消费者模型。

  模型简介:该模型是一个典型的排队内容。模型分为三个主要角色:生产者、消费者、仓库。生产者和消费者共享仓库信息,①当仓库里面的产品满了,停止生产等待消费者去消费到足够的量再进行生产  ②当仓库里面的产品为空,等待生产者生产后再进行销售  ③仓库负责承载产品内容

  根据模型内容,做成了一个车位管理的例子。分为三个角色:持车人(CarOwner)、保安(Secure)、车库(CarPark)。不同的持车人把车驶入到车库,保安负责记录车辆离开车库的数量。车库容量固定,如果车库为空保安可以通知持车人把车驶入车库。如果车库满了,保安告知持车人等待另外的持车人把车驾驶出来。车库使用一个列表对入库的车信息进行记录。

  因此有如下类图:

  

 1 package com.scl.thread.threadPool.CarParkManager;
 2
 3 public class CarOwner implements Runnable
 4 {
 5     private int driverInNum;
 6     private CarPark carPark;
 7
 8     public CarOwner(CarPark carPark)
 9     {
10         this.carPark = carPark;
11     }
12
13     @Override
14     public void run()
15     {
16         carPark.driverIn(driverInNum);
17     }
18
19     public int getDriverInNum()
20     {
21         return driverInNum;
22     }
23
24     public void setDriverInNum(int driverInNum)
25     {
26         this.driverInNum = driverInNum;
27     }
28 }

持车人 CarOwner

停车场 CarPark

 1 package com.scl.thread.threadPool.CarParkManager;
 2
 3 public class Car
 4 {
 5     private String id;
 6     private String name;
 7
 8     public Car(String id, String name)
 9     {
10         this.id = id;
11         this.name = name;
12     }
13
14 }

汽车信息类 Car

 1 package com.scl.thread.threadPool.CarParkManager;
 2
 3 public class Secure implements Runnable
 4 {
 5     private int driverOutNum;
 6
 7     private CarPark carPark;
 8
 9     public Secure(CarPark carPark)
10     {
11         this.carPark = carPark;
12     }
13
14     public int getDriverOutNum()
15     {
16         return driverOutNum;
17     }
18
19     public void setDriverOutNum(int driverOutNum)
20     {
21         this.driverOutNum = driverOutNum;
22     }
23
24     @Override
25     public void run()
26     {
27         carPark.driverOut(driverOutNum);
28     }
29 }

保安 Secute

 1 package com.scl.thread.threadPool.CarParkManager;
 2
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5
 6 public class Client
 7 {
 8
 9     public static void main(String[] args)
10     {
11         // 设置车库最大值
12         CarPark carPark = new CarPark(5);
13         // 创建线程池
14         ExecutorService threadPool = Executors.newCachedThreadPool();
15         // 创建三个持车人
16         CarOwner cw1 = new CarOwner(carPark);
17         CarOwner cw2 = new CarOwner(carPark);
18         CarOwner cw3 = new CarOwner(carPark);
19         // 设置需要驶入的车辆数目
20         cw1.setDriverInNum(3);
21         cw2.setDriverInNum(3);
22         cw3.setDriverInNum(1);
23
24         // 创建三个保安
25         Secure s1 = new Secure(carPark);
26         Secure s2 = new Secure(carPark);
27         Secure s3 = new Secure(carPark);
28         s1.setDriverOutNum(1);
29         s2.setDriverOutNum(2);
30         s3.setDriverOutNum(1);
31
32         threadPool.submit(cw1);
33         threadPool.submit(cw2);
34         threadPool.submit(cw3);
35         threadPool.submit(s1);
36         threadPool.submit(s2);
37         threadPool.submit(s3);
38
39     }
40
41 }

客户端 Client

由上述代码可见,使用线程池和使用Thread类进行提交没有太大的差异。JDK5提供了一个阻塞队列的,能够更好地模拟生产者-消费者模型。后续再进行总结。

以上为线程池的总结内容,如有错漏烦请指出纠正。

时间: 2024-07-31 23:09:06

Java多线程(四) 线程池的相关文章

JAVA多线程(三) 线程池和锁的深度化

github演示代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/src/main/java/com/kawa/thread 1.线程池 1.1 线程池是什么 Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池能够带来3个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务

Java多线程和线程池(转)

1.为什么要使用线程池 在java中,如果每个请求到达就创建一个新线程,开销是相当大的.在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多.除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源.如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足.为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源

java 多线程和线程池

● 多线程 多线程的概念很好理解就是多条线程同时存在,但要用好多线程确不容易,涉及到多线程间通信,多线程共用一个资源等诸多问题. 使用多线程的优缺点: 优点: 1)适当的提高程序的执行效率(多个线程同时执行). 2)适当的提高了资源利用率(CPU.内存等). 缺点: 1)占用一定的内存空间. 2)线程越多CPU的调度开销越大. 3)程序的复杂度会上升. 对于多线程的示例代码感兴趣的可以自己写Demo啦,去运行体会,下面我主要列出一些多线程的技术点. synchronized 同步块大家都比较熟悉

跟我学Java多线程——ThreadPoolExecutor(线程池)

什么是线程池 多线程开发中,由于线程数量多,并且每个线程执行一段时间就结束,所以要频繁的创建线程,但是这样频繁的创建线程会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间.在这种情况下,人们就想要一种可以线程执行完后不用销毁,同时该线程还可以去执行其他任务,在这样的情况下线程池就出现了. 线程池就是线程的池子,任务提交到线程池后,就从线程池中取出一个空闲的线程为之服务,服务完后不销毁该线程,而是将该线程还回到线程池中. 在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,

java多线程、线程池的实现

Java实现多线程的3种方法:继承Thread类.实现runnable接口.使用ExecutorService,Callable.Future实现有返回值的多线程.前2种线程的实现方式没有返回值,第三种实现方式可以获取线程执行的返回值. 一:继承java.lang.Thread类 public class MyThread extends Thread { @Override public void run() { System.out.println( "my thread begin.&qu

java多线程之线程池

自JDK5之后,Java推出了一个并发包,java.util.concurrent,在Java开发中,我们接触到了好多池的技术,String类的对象池.Integer的共享池.连接数据库的连接池.Struts1.3的对象池等等,池的最终目的都是节约资源,以更小的开销做更多的事情,从而提高性能. 我们的web项目都是部署在服务器上,浏览器端的每一个request就是一个线程,那么服务器需要并发的处理多个请求,就需要线程池技术,下面来看一下Java并发包下如何创建线程池. 1.  创建一个可重用固定

java 多线程以及线程池

1.多线程可以使程序反应更快,交互性更强,执行效率最高. 2.创建一个线程:  要实现Runnable 接口,创建Thread类的对象,用start开始执行线程. 3.使用Thread中的yield()方法为其他线程临时让出CPU时间. 4.sleep()方法可以将线程设置为休眠状态以确保其他线程执行.休眠时间为毫秒数·. sleep()方法可能抛出一个InterruptedException.这是一个必捡异常.需要try-catch块中. 5.java为每个线程都设置一个优先级.默认情况下,线

Java 多线程:线程池实现原理

前言 我们都知道,所谓线程池,那么就是相当于有一个池子,线程就放在这个池子中进行重复利用,能够减去了线程的创建和销毁所带来的代价.但是这样并不能很好的解释线程池的原理,下面从代码的角度分析一下线程池的实现. 线程池的相关类 对于原理,在 Java 中,有几个接口,类 值得我们关注: Executor ExecutorService AbstractExecutorService ThreadPoolExecutor Executor public interface Executor {    

Java多线程回顾-线程池---学习笔记(三)

线程池产生原因: 创建很多线程造成的两个问题: 1.构建一个新的线程会涉及到与操作系统的交互,会消耗一定的系统资源,当使用完这些新创建的线程后,线程就会被销毁,然后当我们再创建的时候就会再次消耗系统资源,所以如果创建很多生命期很短的线程,就会消耗很大的系统资源,甚至给系统带来很大的压力. 2.现在不考虑重复创建很多线程造成的压力,单单从创建大量的线程并发执行任务这一点考虑,我们的系统能承受的线程数量是有限的,创建大量的线程会大大降低性能甚至是虚拟机崩溃. 所以这里为了解决创建多个线程造成的这两个