导航:首页 > 编程语言 > java线程池源码

java线程池源码

发布时间:2022-04-22 08:37:39

A. 什么是java线程池

多线程是为了能够让计算机资源合理的分配,对于处理不同的任务创建不同的线程进行处理,但是计算机创建一个线程或者销毁一个线程所花费的也是比较昂贵的,有时候需要同时处理的事情比较多,就需要我们频繁的进行线程的创建和销毁,这样花费的时间也是比较多的。为了解决这一问题,我们就可以引用线程池的概念。
所谓线程池就是将线程集中管理起来,当需要线程的时候,可以从线程池中获取空闲的线程,这样可以减少线程的频繁创建与销毁,节省很大的时间和减少很多不必要的操作。
在java中提供了ThreadPoolExecutor类来进行线程的管理,这个类继承于AbstractExecutorService,而AbstractExecutorService实现了ExecutorService接口,我们可以使用ThreadPoolExecutor来进行线程池的创建。
在ThreadPoolExecutor的构造方法中,有多个参数,可以配置不同的参数来进行优化。这个类的源码构造方法为:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)其中每个参数代表的意义分别为
corePoolSize : 线程池中的核心线程数量,当线程池中当前的线程数小于这个配置的时候,如果有一个新的任务到来,即使线程池中还存在空闲状态的线程,程序也会继续创建一个新的线程放进线程池当中
maximumPoolSize: 线程池中的线程最大数量
keepAliveTime:当线程池中的线程数量大于配置的核心线程数量(corePoolSize)的时候,如果当前有空闲的线程,则当这个空闲线程可以存在的时间,如果在keepAliveTime这个时间点内没有新的任务使用这个线程,那么这个线程将会结束,核心线程不会结束,但是如果配置了allowCoreThreadTimeOut = true,则当空闲时间超过keepAliveTime之后,线程也会被结束调,默认allowCoreThreadTimeOut = false,即表示默认情况下,核心线程会一直存在于线程池当中。
unit : 空闲线程保持连接时间(keepAliveTime)的时间单位
workQueue:阻塞的任务队列,用来保存等待需要执行的任务。
threadFactory :线程工厂,可以根据自己的需求去创建线程的对象,设置线程的名称,优先级等属性信息。
handler:当线程池中存在的线程数超过设置的最大值之后,新的任务就会被拒绝,可以自己定义一个拒绝的策略,当新任务被拒绝之后,就会使用hander方法进行处理。
在java中也提供了Executors工具类,在这个工具类中提供了多个创建线程池的静态方法,其中包含newCachedThreadPool、newFixedThreadPool、newScheledThreadPool、newSingleThreadExecutor等。但是他们每个方法都是创建了ThreadPoolExecutor对象,不同的是,每个对象的初始 参数值不一样;

B. JAVA线程池shutdown和shutdownNow的区别

shutDown()当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。shutdownNow()根据JDK文档描述,大致意思是:执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep、wait、Condition、定时锁等应用,interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。上面对shutDown()以及shutDownNow()作了一个简单的、理论上的分析。如果想知道why,则需要亲自打开JDK源码,分析分析。想要分析shutDown()以及shutDownNow()源码,我建议首先要对ThreadPoolExecutor有个大概了解。因为关闭线程池的所有方法逻辑都在ThreadPoolExecutor中处理的。如果你真的想知道为什么,建议看一下我以前写的一篇对ThreadPoolExecutor源码分析的博文,我想这对你比较透彻的了解shutDown()和shutDownNow()的区别以及java线程池原理有很大的帮助。废话少说,要查看源码,首先进入ThreadPoolExecutor的shutDown()方法:Java代码收藏代码publicvoidshutdown(){SecurityManagersecurity=System.getSecurityManager();if(security!=null)security.checkPermission(shutdownPerm);finalReentrantLockmainLock=this.mainLock;mainLock.lock();try{if(security!=null){//(Workerw:workers)security.checkAccess(w.thread);}intstate=runState;if(state

C. java 线程池 工作队列是如何工作的

使用线程池的好处

1、降低资源消耗

可以重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度

当任务到达时,任务可以不需要等到线程创建就能立即执行。

3、提高线程的可管理性

线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控

线程池的工作原理

首先我们看下当一个新的任务提交到线程池之后,线程池是如何处理的

1、线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则执行第二步。

2、线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里进行等待。如果工作队列满了,则执行第三步

3、线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务

线程池饱和策略

这里提到了线程池的饱和策略,那我们就简单介绍下有哪些饱和策略:

AbortPolicy

为Java线程池默认的阻塞策略,不执行此任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute需要try catch,否则程序会直接退出。

DiscardPolicy

直接抛弃,任务不执行,空方法

DiscardOldestPolicy

从队列里面抛弃head的一个任务,并再次execute 此task。

CallerRunsPolicy

在调用execute的线程里面执行此command,会阻塞入口

用户自定义拒绝策略(最常用)

实现RejectedExecutionHandler,并自己定义策略模式

下我们以ThreadPoolExecutor为例展示下线程池的工作流程图

3.jpg

关键方法源码分析

我们看看核心方法添加到线程池方法execute的源码如下:

// //Executes the given task sometime in the future. The task //may execute in a new thread or in an existing pooled thread. // // If the task cannot be submitted for execution, either because this // executor has been shutdown or because its capacity has been reached, // the task is handled by the current {@code RejectedExecutionHandler}. // // @param command the task to execute // @throws RejectedExecutionException at discretion of // {@code RejectedExecutionHandler}, if the task // cannot be accepted for execution // @throws NullPointerException if {@code command} is null // public void execute(Runnable command) { if (command == null) throw new NullPointerException(); // // Proceed in 3 steps: // // 1. If fewer than corePoolSize threads are running, try to // start a new thread with the given command as its first // task. The call to addWorker atomically checks runState and // workerCount, and so prevents false alarms that would add // threads when it shouldn't, by returning false. // 翻译如下: // 判断当前的线程数是否小于corePoolSize如果是,使用入参任务通过addWord方法创建一个新的线程, // 如果能完成新线程创建exexute方法结束,成功提交任务 // 2. If a task can be successfully queued, then we still need // to double-check whether we should have added a thread // (because existing ones died since last checking) or that // the pool shut down since entry into this method. So we // recheck state and if necessary roll back the enqueuing if // stopped, or start a new thread if there are none. // 翻译如下: // 在第一步没有完成任务提交;状态为运行并且能否成功加入任务到工作队列后,再进行一次check,如果状态 // 在任务加入队列后变为了非运行(有可能是在执行到这里线程池shutdown了),非运行状态下当然是需要 // reject;然后再判断当前线程数是否为0(有可能这个时候线程数变为了0),如是,新增一个线程; // 3. If we cannot queue task, then we try to add a new // thread. If it fails, we know we are shut down or saturated // and so reject the task. // 翻译如下: // 如果不能加入任务到工作队列,将尝试使用任务新增一个线程,如果失败,则是线程池已经shutdown或者线程池 // 已经达到饱和状态,所以reject这个他任务 // int c = ctl.get(); // 工作线程数小于核心线程数 if (workerCountOf(c) < corePoolSize) { // 直接启动新线程,true表示会再次检查workerCount是否小于corePoolSize if (addWorker(command, true)) return; c = ctl.get(); } // 如果工作线程数大于等于核心线程数 // 线程的的状态未RUNNING并且队列notfull if (isRunning(c) && workQueue.offer(command)) { // 再次检查线程的运行状态,如果不是RUNNING直接从队列中移除 int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) // 移除成功,拒绝该非运行的任务 reject(command); else if (workerCountOf(recheck) == 0) // 防止了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。 // 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务 addWorker(null, false); } // 如果队列满了或者是非运行的任务都拒绝执行 else if (!addWorker(command, false)) reject(command); }

D. Java线程池中的核心线程是如何被重复利用的

Java线程池中的核心线程是如何被重复利用的?

引言

在Java开发中,经常需要创建线程去执行一些任务,实现起来也非常方便,但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。此时,我们很自然会想到使用线程池来解决这个问题。

使用线程池的好处:

E. java线程池怎么实现

要想理解清楚java线程池实现原理,明白下面几个问题就可以了:

(1):线程池存在哪些状态,这些状态之间是如何进行切换的呢?

(2):线程池的种类有哪些?

(3):创建线程池需要哪些参数,这些参数的具体含义是什么?

(4):将任务添加到线程池之后运行流程?

(5):线程池是怎么做到重用线程的呢?

(6):线程池的关闭

首先回答第一个问题:线程池存在哪些状态;

查看ThreadPoolExecutor源码便知晓:

[java]view plain

F. 什么样的java线程池可以使用处理数据从插座吗

Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

(1) newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

Java代码

选择我们运行的程序:

监控运行状态

G. java线程池有哪些

一:newCachedThreadPool
(1)缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse,如果没有,就建立一个新的线程加入池中;
(2)缓存型池子,通常用于执行一些生存周期很短的异步型任务;因此一些面向连接的daemon型server中用得不多;
(3)能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。
(4)注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止

二:newFixedThreadPool
(1)newFixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程
(2)其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子
(3)和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器
(4)从方法的源代码看,cache池和fixed 池调用的是同一个底层池,只不过参数不同:
fixed池线程数固定,并且是0秒IDLE(无IDLE)
cache池线程数支持0-Integer.MAX_VALUE(显然完全没考虑主机的资源承受能力),60秒IDLE

三:ScheledThreadPool
(1)调度型线程池
(2)这个池子里的线程可以按schele依次delay执行,或周期执行
四:SingleThreadExecutor
(1)单例线程,任意时间池中只能有一个线程
(2)用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)

H. Java的线程池,如何设定保留的最小线程数和固定的队列容量

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。

看代码:
Java代码 收藏代码
package test;

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

public class ExecutorTest {
public static void main(String args[]) {
Random random = new Random();
//产生一个 ExecutorService 对象,这个对象带有一个大小为 poolSize 的线程池,若任务数量大于 poolSize ,任务会被放在一个 queue 里顺序执行。
ExecutorService executor = Executors.newFixedThreadPool(3);
// 判断可是线程池可以结束
int waitTime = 500;
for (int i = 0; i < 10; i++) {
String name = "线程 " + i;
int time = random.nextInt(1000);
waitTime += time;
Runnable runner = new ExecutorThread(name, time);
System.out.println("增加: " + name + " / " + time);
executor.execute(runner);
}
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException ignored) {
}
}
}

class ExecutorThread implements Runnable {
private final String name;
private final int delay;
public ExecutorThread(String name, int delay) {
this.name = name;
this.delay = delay;
}
public void run() {
System.out.println("启动: " + name);
try {
Thread.sleep(delay);
} catch (InterruptedException ignored) {
}
System.out.println("完成: " + name);
}
}

I. 寻Java 线程池demo

public class ThreadPoolMain extends Object {

public static Runnable makeRunnable(final String name, final long firstDelay) {

return new Runnable() {
public void run() {
try {
System.out.println(name + ": starting up");
Thread.sleep(firstDelay);
System.out.println(name + ": doing some stuff");
Thread.sleep(2000);
System.out.println(name + ": leaving");
} catch (InterruptedException ix) {
System.out.println(name + ": got interrupted!");
return;
} catch (Exception x) {
x.printStackTrace();
}
}

public String toString() {
return name;
}
};
}

public static void main(String[] args) {
try {
ThreadPool pool = new ThreadPool(3);

Runnable ra = makeRunnable("RA", 3000);
pool.execute(ra);

Runnable rb = makeRunnable("RB", 1000);
pool.execute(rb);

Runnable rc = makeRunnable("RC", 2000);
pool.execute(rc);

Runnable rd = makeRunnable("RD", 60000);
pool.execute(rd);

Runnable re = makeRunnable("RE", 1000);
pool.execute(re);

pool.stopRequestIdleWorkers();
Thread.sleep(2000);
pool.stopRequestIdleWorkers();

Thread.sleep(5000);
pool.stopRequestAllWorkers();
} catch (InterruptedException ix) {
ix.printStackTrace();
}
}
}

阅读全文

与java线程池源码相关的资料

热点内容
数控铣床法兰克子程序编程 浏览:173
linux打包命令targz 浏览:996
抖音app是哪个 浏览:407
苹果app怎么上架 浏览:255
NA服务器地址 浏览:427
我的世界如何初始化服务器 浏览:97
哪个手机app天气预报最准 浏览:752
怎样把视频压缩至25m 浏览:570
vivox27文件夹怎么改变 浏览:727
新手玩狼人杀用什么app 浏览:615
pdf在线查看 浏览:954
安卓tv90如何关闭后台 浏览:683
php读取word乱码 浏览:755
minicom源码 浏览:1001
海尔冷柜压缩机 浏览:416
联通服务器如何调试信号 浏览:136
stata新命令 浏览:941
单调栈算法python 浏览:606
微信解压游戏怎么下载 浏览:962
忍三服务器不同如何登上账号 浏览:822