如果要问我Java当中最难的部分是什么?最有意思的部分是什么?最多人讨论的部分是什么?那我会毫不犹豫地说:多线程。

Java多线程说它难,也不难,就是有点绕;说它简单,也不简单,需要理解的概念很多,尤其是很多底层知识,如数据结构、操作系统的部分。

Java多线程掌握得好,不仅仅只是对Java,对任何其他具有并发特性的编程语言,甚至是操作系统,都能有更全面和准确的认识。

Java多线程最大的特点,而且也是唯一确定的一件事,那就是:在多线程环境下,程序的运行结果是无法预料的,但这也正是它最有趣的地方。

在了解多线程之前,最好先知道什么是并发,什么是并行。不然很容易迷糊。

总的来说,就是这样:

并行:同一时刻可以同时发生/执行多个任务。

并发:同一时刻只能发生/执行一个任务。


学习多线程最好从如下六个方面循序渐进(纯粹个人经验和建议,可无视):

1、线程生命周期:NEW、RUNNABLE(READY、RUNNING)、BLOCKED、WAITING、TIMED_WAITING、TERMINATED状态

2、关键字:synchronized和volatile

3、线程池:ThreadPoolExecutor

4、锁(AQS):悲观锁/乐观锁、轻量级锁/重量级锁、自旋锁/可重入锁等各种锁

5、CAS:各种原子类

6、并发工具类:ArrayBlockingQueue、CountDownLatch、CyclicBarrier、Semaphore等


Java多线程用一句话总结就是「6类5法」。

所谓「6类」,就是多状态的状态分为这6类:

1、新建(NEW):新创建了一个线程,但还没调用start方法

2、运行(RUNNABLE)

2.1、就绪(ready):运行start方法后,线程位于可运行线程池中,等待被调度

2.2、运行中(RUNNING):就绪的线程获得CPU的时间片就变为运行中

3、阻塞(BLOCKED):线程等待获取锁

4、等待(WAITING):接收事件通知后或系统中断后进入等待

5、超时(TIMED_WAITING):等待指定时间后会自行返回

6、终止(TERMINATED):线程已执行完毕

这是线程生命周期的状态变化图:

简单来说,就是这样:

而所谓「5法」就是线程的核心方法是这么5个:

1、wait:当前线程调用锁对象的wait方法,当前线程释放锁,进入等待状态,由其他线程接着执行

2、notify/notifyAll:唤醒任意一个或全部等待的线程后接着执行,但并不释放锁

3、join:当前线程调用其他线程的join方法,调用后当前线程进入等待状态

4、yield:当前线程调用,调用后暂停执行(可能无效),变为就绪态

5、sleep:当前线程调用,调用后进入TIME_WAITING状态


用代码来解释一下会更直观一些。

第一种wait/notify的情况:

public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
System.out.println("t1 start");
try {
// t1释放锁
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
System.out.println("t2 start");
try {
// 通知t1进入等待队列
"锁".notify();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t2 end");
}
}
}); t1.start();
t2.start();
}

此时代码执行流程(两种可能):

1、T1先执行

  1.1、T1启动,wait让出锁,让出CPU,T2获得CPU,T2启动,notify了通过object锁等待的线程

  1.2、T1被唤醒后等待启动,T2继续执行,T2执行完,T1获得CPU后继续执行

2、T2先执行

  2.1、T2执行完,T1启动,让出CPU,由于没有线程再来执行notify,程序无限期等待

这里要强调的重点是:

1、wait会让出CPU而notify不会

2、wait重点在通知其它同用一个object的线程“我暂时不用了”,并且让出CPU

3、notify重点在于通知使用object的对象“我用完了!”

如果说只有两个线程的时候,还能尝试着分析一下结果,那么当有四个线程的时候会如何呢?看看代码:

public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
System.out.println("t1 start");
try {
// t1释放锁
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
try {
System.out.println("t2 start");
// 随机通知一个等待的线程进入等待队列
"锁".notify();
System.out.println("t2 end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}); Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
try {
System.out.println("t3 start");
// 随机通知一个等待的线程进入等待队列
"锁".notify();
System.out.println("t3 end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
try {
System.out.println("t4 start");
// t4释放锁
"锁".wait();
System.out.println("t4 end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}); t1.start();
t2.start();
t3.start();
t4.start();
}

然后同时开启这四个线程,但结果是无法预料!为什么?因为只有两种可能的流程(要么wait先执行完,要么notify先执行完),至于每种流程里面怎么执行的?不知道!不清楚!无法预料!这就是多线程让人困惑的地方和魅力所在。

而且线程还有一个无赖的行为就是:虽然你有优先级,但我不保证有用!

public class MyThread extends Thread {
MyThread(String s) {
super(s);
} @Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println(getName() + " : " + i);
if (i == 5) {
Thread.yield();
}
}
} public static void main(String[] args) throws InterruptedException {
System.out.println("主线程启动");
Thread t1 = new MyThread("t1");
Thread t2 = new MyThread("t2");
t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.setPriority(Thread.MAX_PRIORITY);
t2.start();
t1.join();
t2.join();
System.out.println("主线程结束");
}
}

这里不管怎么设置t1或者t2的优先级,都没有用,运行的结果每次都可能不一样。

线程的生命周期6类5法算是比较简单的,是基础中的基础。但是用好很难,关键在于多练多想,多多尝试各种组合。

Java多线程-线程生命周期(一)的更多相关文章

  1. Java多线程:生命周期,实现与调度

    Java线程生命周期 Java线程实现方法 继承Thread类,重写run()方法 实现Runnable接口,便于继承其他类 Callable类替换Runnable类,实现返回值 Future接口对任 ...

  2. Java多线程-线程的生命周期

    线程可以分为4个状态:New(新生),Runnable(可运行):为了方便分析,还可将其分为:Runnable与Running.blocked(被阻塞),Dead(死亡). 与人有生老病死一样,线程也 ...

  3. Java多线程——线程的优先级和生命周期

    Java多线程——线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  4. Java多线程与并发——线程生命周期和线程池

    线程生命周期:  线程池:是预先创建线程的一种技术.线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中,然后对这些资源进行复用.减少频繁的创建和销毁对象. java里面线程池的顶级接口是E ...

  5. [译]线程生命周期-理解Java中的线程状态

    线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...

  6. Java线程生命周期

    当你需要使用Java线程在多线程环境下进行编程时,理解Java的线程周期与线程的状态是非常重要的.通过实现Runnale接口或者继承Thread类,我们可以创建线程,为了启动一个线程,我们需要创建一个 ...

  7. Java线程生命周期与状态切换

    前提 最近有点懒散,没什么比较有深度的产出.刚好想重新研读一下JUC线程池的源码实现,在此之前先深入了解一下Java中的线程实现,包括线程的生命周期.状态切换以及线程的上下文切换等等.编写本文的时候, ...

  8. Java并发编程实战(5)- 线程生命周期

    在这篇文章中,我们来聊一下线程的生命周期. 目录 概述 操作系统中的线程生命周期 Java中的线程生命周期 Java线程状态转换 运行状态和阻塞状态之间的转换 运行状态和无时限等待状态的切换 运行状态 ...

  9. Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt

    Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...

随机推荐

  1. Docke 搭建 apache2 + php8 + MySQL8 环境

    Docker 安装 执行 Docker 安装命令 curl -fsSL https://get.docker.com/ | sh 启动 Docker 服务 sudo service docker st ...

  2. K8s小白?应用部署太难?看这篇就够了!

    在云原生趋势下,容器和 Kubernetes 可谓是家喻户晓,许多企业内部的研发团队都在使用 Kubernetes 打造 DevOps 平台.从最早的容器概念到 Kubernetes 再到 DevOp ...

  3. LibTorch | 使用神经网络求解一维稳态对流扩散方程

    0. 写在前面 本文将使用基于LibTorch(PyTorch C++接口)的神经网络求解器,对一维稳态对流扩散方程进行求解.研究问题参考自教科书\(^{[1]}\)示例 8.3. 目录 0. 写在前 ...

  4. 一文总结高并发大数据量下MySQL开发规范【军规】

    在互联网公司中,MySQL是使用最多的数据库,那么在并发量大.数据量大的互联网业务中,如果高效的使用MySQL才能保证服务的稳定呢?根据本人多年运维管理经验的总结,梳理了一些核心的开发规范,希望能给大 ...

  5. python自动更新pom文件

    前言 项目越来越多,版本管理越来越麻烦,在项目上我使用 maven version 来进行版本管理.主要还是在分布式项目中模块众多的场景中使用,毕竟各个模块对外的版本需要保持统一. 关于这个插件如何使 ...

  6. 分布式MinIO快速入门

    官方文档地址:http://docs.minio.org.cn/docs/master/distributed-minio-quickstart-guide Minio服务基于命令行传入的参数自动切换 ...

  7. Elasticsearch集群规模和容量规划的底层逻辑

    转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484628&idx=1&sn=666e416ae ...

  8. 第五章:Admin管理后台 - 3:Admin文档生成器

    Django的admindocs应用可以从模型.视图.模板标签等地方获得文档内容. 一.概览 要激活admindocs,请按下面的步骤操作: 在INSTALLED_APPS内添加django.cont ...

  9. django-compressor安装失败

    报错日志: Installing collected packages: rcssmin, django-compressor Running setup.py install for rcssmin ...

  10. vscode展示子文件夹

    取消勾选设置-功能-compact Folders