首页 > 其他分享 >线程

线程

时间:2023-03-21 23:01:43浏览次数:35  
标签:状态 队列 任务 线程 null CPU

线程是调度CPU资源的最小单位,线程模型分为KLT模型与ULT模型,JVM使用的是KLT模型,java线程与OS线程保持1:1的映射关系,也就是说有一个java线程也会在操作系统里有一个对应的线程。

Java线程的生命状态:

      NEW 新建

      RUNNABLE 运行

      BLOCKED   阻塞

      WAITING  等待

      TIMED_WAITING  超时等待

      TERMINATED   终结

 

 

 

 线程池

 什么时候使用线程池?

   1. 单个任务处理时间比较短

        2. 需要处理的任务数量很大

 线程池优势:

   1. 重用存在的线程,减少线程创建,消亡的开销,提高性能

   2. 提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。

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

```

int corePoolSize, 核心线程数
int maximumPoolSize, 最大线程数
long keepAliveTime, 最大允许线程不干活的时间
TimeUnit unit, 时间单位
BlockingQueue<Runnable> workQueue, 存放未来得及执行的任务
ThreadFactory threadFactory, 创建线程的工厂
RejectedExecutionHandler handler 拒绝策略

```

 

 

 

 执行流程:

1. 当核心线程数还未满时,此时有个新的任务过来,即使存在空闲的线程,也不会让其执行,还是会新建线程来执行该任务

2. 当核心线程数满了,此时新的任务会往队列中存放,

3. 当队列中满了,此时会新建非核心线程来处理任务

4. 当非核心线程也满了,此时再有新的任务过来,则会执行拒绝策略

注意点:

非核心线程创建并执行完当前任务后,是会继续执行队列中的任务还是直接销毁?

1. 核心线程和非核心线程,都是线程

2. 当新建了线程,线程首先执行任务;执行完成之后会从workQueue队列中取任务。队列可能为空,因此线程取任务可能会阻塞。在从队列获取任务前,线程池会先进行判断,当线程数量>coreSize时,说明可以消减线程了,就会给该线程设置从队列取任务的最长阻塞时间(keepAliveTime),超时返回null,即表示该线程空闲了keepAliveTime时间,并且线程池数大于corePoolSize核心线程数,就会将该线程销毁。

原文链接:https://blog.csdn.net/qq_41257358/article/details/122202547

 

线程池的状态:

 

 

 

1. RUNNING  -1

状态说明:线程池的初始状态,接收新的任务且处理队列中的任务

2. SHUTDOWN  0

状态说明:不接收新的任务,但处理队列中的任务

状态切换:调用线程池的shutdown()接口时,线程池由RUNNING->SHUTDOWN

3. STOP   1

状态说明:既不接收新的任务,也不处理队列中的任务,并且会中断正在处理的任务

状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN)->STOP

4. TIDYING   2

状态说明:当所有的任务已终止,ctl记录的任务数量为0,线程池会变为TIDYING状态.此时会执行钩子函数terminated(),terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理,可以通过重载terminated()函数来实现

状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空,且线程池中执行的任务也为空时,就会由SHUTDOWN->TIDYING.当线程在STOP状态下,线程池中执行的任务为空时,就会由STOP->TIDYING

5. TERMINATED 3

状态说明:线程池彻底终止,就变成了TERMINATED状态

状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由TIDYING->TERMINATED.

进入TERMINATED的条件如下:

5.1 线程池不是RUNNING状态

5.2 线程池状态不是TIDYING或TERMINATED状态

5.3 如果线程池状态是SHUTDOWN并且workerQueue为空

5.4 workCount为0

5.5 设置TIDYING状态成功

 

拒绝策略

当非核心线程都处理不了任务时,则执行拒绝策略

AbortPolicy:默认执行策略,直接往外抛异常

CallerRunsPolicy:如果线程池没有关闭,则由当前线程自己执行该任务

DiscardPolicy:不处理当前任务,即丢弃当前任务

DiscardOldestPolicy:丢弃最老的任务,将新任务放入队列

 

ThreadPoolExecutor.runWorker :循环获取任务,这也是为什么线程能重用的原因

```

final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
    // 循环,判断任务是否还有未执行的,获取到则执行
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}

```

getTask(),

```

private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
     //allowCoreThreadTimeOut 允许核心线程超时:默认是false,可以手动设置为true,线程小于corePoolSize数,则为false
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
          // 阻塞队列,当队列为空,则阻塞,阻塞时间keepAliveTime,
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
          // 没有时间限制,核心线程就可以一直等待,当队列中新增任务后,就会唤醒线程
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}

```

获取不到任务后,就执行该方法processWorkerExit

```

private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();

final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
    // 移除线程
workers.remove(w);
} finally {
mainLock.unlock();
}

tryTerminate();

int c = ctl.get();
// 判断当前的线程池的状态是否为RUNNING或shutdown
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
    // 新增非核心线程
addWorker(null, false);
}
}

```

 

线程数量设置:

CPU密集型:cpu核数+1,CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作CPU读写IO(硬盘/内存)时,IO可以在很短的时间内完成,而CPU还有许多运算要处理,因此,CPU负载很高。

IO密集型:2cpu核数+1,IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等IO (硬盘/内存) 的读写操作,因此,CPU负载并不高。

标签:状态,队列,任务,线程,null,CPU
From: https://www.cnblogs.com/wanthune1/p/17241948.html

相关文章

  • java线程池相关问题
    线程池有几种拒绝策略?当线程池的线程数达到最大线程数时,需要执行拒绝策略。拒绝策略需要实现RejectedExecutionHandler接口,并实现rejectedExecution(Runnabler, T......
  • 【Thread -- 1.1】 实现多线程的正确姿势
    【Thread--1.1】实现多线程的正确姿势一、实现多线程的方法有几种--两种1、正确方法--Oraclle官方文档--2种[Oraclle官方文档](Overview(JavaPlatformSE8)(ora......
  • JUC——什么是线程死锁?如何避免死锁?
      下面通过一个例子来说明线程死锁,代码模拟了上图的死锁的情况(代码来源于《并发编程之美》):publicclassDeadLockDemo{privatestaticObjectresource1=......
  • 守护线程和用户线程
    用户线程:主线程的子线程,当主线程结束时,用户线程也会结束。守护线程:一种特殊的线程,它是在后台运行的,当所有用户线程结束时,守护线程也会随之结束。例如gc线程 publiccl......
  • fastapi多线程非阻塞启动
    1问题描述我在run.py文件下的主函数如下所示:importuvicornfromfastapiimportFastAPIapp=FastAPI(title="chatglm",description="开源版的chatglm接......
  • Java ThreadPoolTaskExecutor 线程池的常见问题
    JavaThreadPoolTaskExecutor线程池的常见问题 https://blog.csdn.net/weixin_43611528/article/details/123083314 重要参数corePoolSize:核心线程数,常开的线程数,默......
  • 【python】多线程并发,rpc接口性能测试
    1、官方文档https://docs.python.org/3/library/concurrent.futures.html 2、安装python3.x中自带了concurrent.futures模块python2.7需要安装futures模块,使用命令......
  • 面试常考:C#用两个线程交替打印1-100的五种方法
      "C#用两个线程交替打印1-100的五种方法"是.NET工程师面试多线程常考的试题之一,主要考察对C#语法和对多线程的熟悉程度。本文将用5种方法实现这个面试题。方法1:使用M......
  • javaSE-day12(多线程)
    1.多线程的常用方法Thread提供了很多与线程操作相关的方法方法:publicvoidrun():线程的任务方法publicvoidstart():启动线程publicStringgetName():获取当前......
  • C++温故补缺(十五):多线程
    多线程参考:CSDN,知乎传统C++(C++11之前)中并没有引入线程的概念,如果想要在C++中实现多线程,需要借助操作系统平台提供的API,如Linux的<pthread.h>,或windows下的<windows.......