4.线程池详解 您所在的位置:网站首页 java线程池是什么 4.线程池详解

4.线程池详解

2024-06-14 11:36| 来源: 网络整理| 查看: 265

目录

线程池

1.为什么使用线程池(优势)

2.线程池底层原理

3.几种线程池如何工作的?

4.几种线程池的使用Demo

5.使用线程池好处

 

线程池 1.为什么使用线程池(优势) 我们使用线程的时候就去创建一个线程,这样实现起来非常简单,但是就会出现一个问题:如果并发的线程数量很多,并且每一个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是继续执行其它任务,在java中可以通过线程池来表达这样的效果。 2.线程池底层原理 线程池可以理解为容器(集合),一般使用集合(ArrayList,HashSet,LinkedList,HashMap)来充当容器,常用LinkedList集合作为容器,泛型就是线程即集合中存放的都是线程。下面是在LinkedList集合中通过add方法向集合中添加一些线程即add(new Thread(xxx))。1.当程序第一次启动时,创建多个线程,保存到一个集合中。2.当我们想要使用线程的时候,就可以从集合中取出线程使用。  Thread t=list.remove(0):从List集合中移除第0个线程(线程只能被一个任务使用)Thread t=linked.removeFirst():从LikedList集合中移除第1个线程3.当我们使用完线程,需要将线程归还给线程池:即将线程再添加到集合中,(这里面有队列机制,从对头取出,队尾归还) 若是List集合,则list.add(t);将线程归还到list集合末尾若是LinkedList集合,则linked.addLast(t);将线程归还到LinkedList集合尾端。

注意:

JDK1.5之后,JDK内置了线程池,我们可以直接使用。

3.几种线程池如何工作的?

任务加入后各个线程池执行流程:

缓存线程池

1.判断线程池是否存在空闲线程,存在则使用,不存在则创建线程放入线程池再使用。2.长度无限制。

定长线程池

判断线程池是否存在空闲线程,存在则使用不存在空闲线程,且线程池未满,则创建线程放入线程池,再使用。不存在空闲线程,且线程池已满,则等待出现空闲线程再使用线程池线程长度是指定的数值。

单线程线程池

判断线程池的那个线程是否空闲,空闲则使用,不空闲则等待这个线程空闲再用。池中只有一个线程,相当于获取定长线程池传参1效果。

周期定长线程池

判断线程池是否存在空闲线程,存在则使用。不存在空闲线程,且线程池未满,则创建线程放入线程池,然后使用。不存在空闲线程,且线程池已满,则等待线程池存在空闲线程。实现定时执行或定时周期执行任务,当某个时机触发时,自动执行某个任务。

4.几种线程池的使用Demo

线程池:JDK1.5之后提供的

1.java.util.concurrent.Executors:线程池工厂类,用来创建线程池2.Executors类中的静态方法: static ExecutorService newFixedThreadPool(int nThreads){} 创建一个可重用 固定线程数的线程池 参数:int nThreads:创建线程池中包含的线程数量 返回值:返回的是ExecutorService接口的实现类对象,可以使用该接口接收(面向接口编程) 3.java.util.concurrent.ExecutorService:线程池接口 用来从线程池中获取线程,调用start方法,执行线程任务submit(Runnable task)提交一个Runnable任务用于执行关闭/销毁线程池的方法void shutdowm()

 * 4.线程池的使用步骤:

1.使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool创建一个指定线程数量的线程池,并用ExecutorService接口接收。 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务 3.调用ExecutorService中方法submit,传递线程任务(实现类),开启线程,执行run方法4.调用ExecutorService中的方法shutdown销毁销毁线程池(不建议) package Thread.demo17.ThreadPool; /** * 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务 */ public class RunnableImpI implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"创建一个新的" +"线程执行"); } } package Thread.demo17.ThreadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo1ThreadPool { public static void main(String[] args) { //1.使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool // 创建一个指定线程数量的线程池,并用ExecutorService接口接收。 ExecutorService es= Executors.newFixedThreadPool(2);//两个线程 //3.线程池调用ExecutorService中submit,传递线程任务(实现类),开启线程,执行run方法 //传递三个线程任务,这三个线程任务相同,也可以创建多个实现类(线程任务) es.submit(new RunnableImpI());//pool-1-thread-2创建一个新的线程执行 es.submit(new RunnableImpI());//pool-1-thread-1创建一个新的线程执行 //线程池会一直开启,使用完了线程,会自动把线程归还线程池,线程可以继续使用 es.submit(new RunnableImpI());//pool-1-thread-1创建一个新的线程执行 //4.调用ExecutorService中的方法shutdown销毁销毁线程池(不建议) es.shutdown(); } }

CachedThreadPool

package demo24threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 缓存线程池的使用 * 1.判断线程池是否存在空闲线程,存在则使用,不存在则创建线程放入线程池再使用。 * 2.长度无限制。 */ public class CachedThreadPool { public static void main(String[] args) { //获取缓存线程池 ExecutorService service = Executors.newCachedThreadPool(); //指挥线程池执行线程任务(线程任务使用匿名内部类写法) service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"你好啊"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"我很好"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"我也很好"); } }); try { Thread.sleep(5000); System.out.println("休眠5s"); } catch (InterruptedException e) { e.printStackTrace(); } service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"我还好"); } }); } }

FixedThreadPool

package demo24threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 定长线程池:即指定线程池线程数量 * 判断线程池是否存在空闲线程,存在则使用 * 不存在空闲线程,且线程池未满,则创建线程放入线程池,再使用。 * 不存在空闲线程,且线程池已满,则等待出现空闲线程再使用 * 线程池线程长度是指定的数值。 */ public class FixedThreadPool { public static void main(String[] args) { //获取定长线程池,设置池中线程数为2 ExecutorService service = Executors.newFixedThreadPool(2); //线程池分配线程执行线程任务(任务使用匿名内部类) service.execute(new Runnable() { @Override public void run() { try { System.out.println("线程1开始执行任务1,此处休眠3s,线程1一直被占用"); Thread.sleep(3000); System.out.println("休眠结束,线程1继续执行线程任务"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+"任务1:你好啊"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"任务2:我很好"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"任务3:我也很好"); } }); } }

SingleThreadPool

package demo24threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 单线程线程池: * 判断线程池的那个线程是否空闲,空闲则使用,不空闲则等待这个线程空闲再用。 * 池中只有一个线程,相当于获取定长线程池传参1效果 */ public class SingleThreadPool { public static void main(String[] args) { //获取单线程线程池 ExecutorService service = Executors.newSingleThreadExecutor(); //线程池分配线程执行线程任务 service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"你好啊"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"我很好"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+"我也很好"); } }); } }

ScheduledThreadPool

package demo24threadpool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 周期定长线程池 * * 判断线程池是否存在空闲线程,存在则使用。 * 不存在空闲线程,且线程池未满,则创建线程放入线程池,然后使用。 * 不存在空闲线程,且线程池已满,则等待线程池存在空闲线程。 * 实现定时执行或定时周期执行任务,当某个时机触发时,自动执行某个任务。 */ public class ScheduledThreadPool { public static void main(String[] args) { //获取周期定长线程池,设置池中线程数为2 ScheduledExecutorService service = Executors.newScheduledThreadPool(2); //线程池分配线程执行线程任务 //1.定时执行一次,定时3s后执行 //参数1:为要定时执行的任务 //参数2:设置定时时长 //参数3:设置时长单位,使用TimeUnit工具类中常量指定 service.schedule(new Runnable(){ @Override public void run() { System.out.println("定时3s后线程执行线程任务"); System.out.println(Thread.currentThread().getName() + ";你好啊"); } }, 3, TimeUnit.SECONDS); //2.周期执行任务,5s后每隔1s执行一次任务 //参数1:线程任务 //参数2:延迟时长(即第一次执行在什么时间以后) //参数3:周期时长(每隔多久执行一次) //参数4:时长单位,使用TimeUnit工具类 service.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("5s后每隔1s执行一次线程任务"); System.out.println(Thread.currentThread().getName() + ";你好啊"); } },5,1,TimeUnit.SECONDS); } } 5.使用线程池好处 1.降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。2.提高响应速度。当任务到达时,任务不需要等到线程创建就能立即执行。3.提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器搞垮(每个线程需要大约1MB,线程开的越多,消耗的内存也就越大)

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有