Java多线程一次给你整明白

1.4 线程的状态


sleep、yield 和 join 区别:

  • sleep 执行后线程进入阻塞状态,当前线程休眠一段时间

  • yield 执行后线程进入就绪状态,使当前线程和所有等待的线程一起进行竞争 CPU 资源

  • join执行线程进入阻塞状态,t.join 表示阻塞调用此方法的线程,直到线程 t 完成,方可继续执行。底层实际调用 wait 方法

  1. 新建状态(New):线程对象被创建后,就进入了新建状态。例如:Thread thread = new Thread()

  2. 就绪状态(Runnable):也被称为"可执行状态"。线程对象呗创建后,其它线程调用了该对象的 start() 方法,从而就启动该线程。例如T.stat(),处于就绪状态的线程,随时可能被CPU调度执行

  3. 运行状态(Running):线程获取 CPU 权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态

  4. 阻塞状态(Blocked):阻塞状态是线程放弃CPU使用权,暂时停止运行,直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

  5. 等待阻塞:通过调用线程的wait() 方法,让线程等待某工作的完成

  6. 同步阻塞:线程在获取 synchronized 同步锁失败,它会进入同步阻塞状态

  7. 其它阻塞:通过调用线程的 sleep() 或 join() 或发出 I/O 请求时,线程会进入到阻塞状态。当 sleep() 状态超时,join() 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入到就绪状态

  8. 死亡状态(Dead):线程执行完了或者因异常退出了 run() 方法,该线程结束生命周期

2.多线程的实现方式

==========

2.1继承 Thread 类创建线程


Thead 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例

复制代码

1 /**

2 * @description: 多线程实现方法1:集成Thread类

3 * @author: DZ

4 **/

5 @Slf4j

6 public class MyThread1 extends Thread {

7 @Override

8 public void run() {

9 log.info(“MyThread1”);

10 log.info(“MyThread2”);

11 }

12 ​

13 public static void main(String[] args) {

14 MyThread1 t1 = new MyThread1();

15 MyThread1 t2 = new MyThread1();

16 t1.start();

17 t2.start();

18 }

19 }

复制代码

2.2实现 Runnable 接口创建线程


如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时可以通过实现 Runnable 接口

避免单继承的局限性、适合多个相同的线程去处理同一个资源

复制代码

1 /**

2 * @description: 多线程实现方法2:实现Runnable接口

3 **/

4 @Slf4j

5 public class MyThread2 implements Runnable {

6 ​

7 @Override

8 public void run() {

9 log.info(“MyThread1”);

10 log.info(“MyThread2”);

11 }

12 ​

13 public static void main(String[] args) {

14 MyThread2 m = new MyThread2();

15 //1.调用run方法

16 Thread t1 = new Thread(m);

17 Thread t2 = new Thread(m);

18 t1.start();

19 t2.start();

20 }

21 }

复制代码

2.3实现 Callable 接口,通过 Future Task 包装器来创建 Thread 线程


可以获取线程的返回值

复制代码

1 /**

2 * @description: 多线程实现方法2:实现Callable接口

3 * @author: DZ

4 **/

5 @Slf4j

6 public class MyThread3 implements Callable {

7 @Override

8 public String call() throws Exception {

9 log.info(“MyThread1”);

10 log.info(“MyThread2”);

11 return “MyThread3”;

12 }

13 ​

14 public static void main(String[] args) throws ExecutionException, InterruptedException {

15 MyThread3 m = new MyThread3();

16 //存储返回值,其中泛型为返回值的类型

17 FutureTask futureTask = new FutureTask<>(m);

18 new Thread(futureTask).start();

19 System.out.println(futureTask.get());

20 }

21 ​

22 }

复制代码

2.4通过线程池


2.4.1 线程池的主要参数

1 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {

2 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

3 Executors.defaultThreadFactory(), defaultHandler);

4 }

  • corePoolSize

当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时,(除了利用提交新任务来创建和启动线程(按需构造),也可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。)

  • maximumPoolSize

线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数

  • keepAliveTime

当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数

  • workQueue

用于传输和保存等待执行任务的阻塞队列

  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列

  • LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列

  • PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列

  • DelayQueue 一个使用优先级队列实现的无界阻塞队列

  • SynchronousQueue 一个不存储元素的阻塞队列

  • LinkedTransferQueue 一个由链表结构组成的无界阻塞队列

  • LinkedBlockingDeque 一个由链表结构组成的双向阻塞队列

**作用:**阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。当队列中有任务时才唤醒对应线程从队列中取出消息进行执行。使得在线程不至于一直占用cpu资源。

  • threadFactory

用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)

  • handler

当线程池和队列都满了,再加入线程会执行此策略

AbortPolicy: 直接抛出异常,阻止线程正常运行

1 public static class AbortPolicy implements RejectedExecutionHandler {

2 public AbortPolicy() {}

3 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

4 throw new RejectedExecutionException(“Task " + r.toString() +” rejected from " + e.toString());

5 }

6 }

CallerRunsPolicy: 直接在方法的调用线程中执行,除非线程池已关闭

复制代码

1 public static class CallerRunsPolicy implements RejectedExecutionHandler {

2 public CallerRunsPolicy() {}

3 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

4 if (!e.isShutdown()) {

5 r.run();

6 }

7 }

8 }

复制代码

DiscardPolica: 丢弃当前的线程任务而不做任何处理。如果系统允许在资源不足的情况下弃部分任务,则这将是保障系统安全、稳定的一种很好的方案

1 public static class DiscardPolicy implements RejectedExecutionHandler {

2 public DiscardPolicy() {}

3 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

4 }

5 }

DiscardOlderPolicy: 移除线程队列中最早(老)的一个线程任务,并尝试提交当前任务

复制代码

1 public static class DiscardOldestPolicy implements RejectedExecutionHandler {

2 public DiscardOldestPolicy() { }

3 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

4 if (!e.isShutdown()) {

5 e.getQueue().poll();// 最早(老)的任务出队列

6 e.execute®;

7 }

8 }

9 }

复制代码

2.4.2如何设置线程池

  • CPU密集型

尽量使用较小的线程池,一般为CPU核心数+1。 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,会造成CPU过度切换。

  • IO密集型任务

可以使用稍大的线程池,一般为2*CPU核心数。 IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候有其他线程去处理别的任务,充分利用CPU时间

  • 混合型任务

线程数 = CPU核心数 * (1+平均等待时间 / 平均工作时间)

2.4.3 代码示例

复制代码

1 import lombok.extern.slf4j.Slf4j;

2 import org.junit.Test;

3 ​

4 import java.util.concurrent.*;

5 ​

6 /**

7 * @description: 通过线程池实现多线程

8 * @author: DZ

9 **/

10 @Slf4j

11 public class MyThread4 {

12 //通常使用方式,定义前5个参数即可,其余默认

13 private ThreadPoolExecutor threadPoolExecutor0 = new ThreadPoolExecutor(5, 10, 60,

14 TimeUnit.SECONDS, new LinkedBlockingQueue(10));

15 ​

16 //所有参数均自定义(增加工厂ThreadFactory和拒绝方式Handle)

17 private ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(5, 10, 60,

18 TimeUnit.SECONDS, new LinkedBlockingQueue(10), new ThreadFactory() {

19 @Override

20 public Thread newThread(Runnable r) {

21 Thread thread = new Thread®;

22 log.info(“我是线程{}”, thread.getName());

23 return thread;

24 }

25 }, new RejectedExecutionHandler() {

26 @Override

27 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

28 log.info(“线程被去掉{}”, new Thread®.getName());

29 }

30 });

31 ​

32 //所有参数均自定义,拒绝方式使用默认new ThreadPoolExecutor.AbortPolicy(),new ThreadPoolExecutor.DiscardOldestPolicy(),new ThreadPoolExecutor.CallerRunsPolicy(),new ThreadPoolExecutor.DiscardPolicy()

33 private ThreadPoolExecutor threadPoolExecutor2 = new ThreadPoolExecutor(5, 10, 60,

34 TimeUnit.SECONDS, new LinkedBlockingQueue(10), new ThreadFactory() {

35 @Override

36 public Thread newThread(Runnable r) {

37 Thread thread = new Thread®;

38 log.info(“我是线程{}”, thread.getName());

39 return thread;

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
架构面试专题及架构学习笔记导图.png

olExecutor.DiscardPolicy()

33 private ThreadPoolExecutor threadPoolExecutor2 = new ThreadPoolExecutor(5, 10, 60,

34 TimeUnit.SECONDS, new LinkedBlockingQueue(10), new ThreadFactory() {

35 @Override

36 public Thread newThread(Runnable r) {

37 Thread thread = new Thread®;

38 log.info(“我是线程{}”, thread.getName());

39 return thread;

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
[外链图片转存中…(img-bu9wQHh6-1714354452015)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值