JUC并发编程上篇
JUC上篇
1.大纲


2.进程与线程
本章内容
- 进程和线程的概念
- 并行和并发的概念
- 线程基本应用
2.1进程与线程
进程:
- 一个程序被运行,从磁盘加载这个程序的代码到内存,就开起了一个进程。
- 进程可以视为程序的一个实例,大部分程序可以同时运行多个实例进程(笔记本,记事本,图画,浏览器等),也有的程序只能启动一个实例进程(网易云音乐,360安全卫士等)。
线程:
- 一个进程内可以分为一到多个线程。
- 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。
- Java中线程是最小调度单元,进程作为资源分配的最小单位。在windows中进程是不活动的,仅仅作为线程的容器。
二者对比
- 进程基本上相互独立的,而线程存在于进程内,是进程的一个子集
- 进程拥有共享的资源,如内存空间等,供其内部的线程共享
- 进程间通信较为复杂
- 同一台计算机的进程通信称为 IPC(Inter-process communication)
- 不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
- 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
- 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低
小结:
| 分类 | 描述 |
|---|---|
| 进程定义 | 程序被运行时,从磁盘加载代码到内存,形成一个进程。进程是程序的一个实例。 |
| 进程示例 | 多实例:记事本、图画、浏览器单实例:网易云音乐、360安全卫士 |
| 线程定义 | 一个进程可以包含一个或多个线程;线程是指令流的执行单元,按照顺序将指令交给 CPU 执行。 |
| Java 中的特点 | Java 中线程是最小调度单元,进程是资源分配的最小单位。在 Windows 中,进程本身是不活动的,仅作为线程的容器。 |
| 对比项 | 进程 | 线程 |
|---|---|---|
| 所属关系 | 独立存在 | 存在于进程内部,是其子集 |
| 资源共享 | 拥有自己的资源;同一进程内线程共享进程资源(如内存) | 共享进程资源(如变量、堆内存) |
| 通信复杂度 | 进程间通信较复杂,需要 IPC 或网络协议(如 HTTP) | 通信简单,可直接通过共享内存通信 |
| 上下文切换成本 | 较高 | 较低,线程更轻量 |
2.2 并行与并发
操作系统任务调度器,可以把CPU时间交给不同线程使用,线程可以轮流使用CPU资源。
- 单核 cpu 下,线程实际还是 串行执行 的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是:微观串行,宏观并行,
一般会将这种 线程轮流使用 CPU 的做法称为并发, concurrent - 多核 cpu下,每个核(core) 都可以调度运行线程,这时候线程可以是并行的。

并发并行:
- 并行:在同一时刻,有多个指令在多个 CPU 上同时执行 同一时间同时做多件事情的能力。多个人做多件事。
- 并发:在同一时刻,有多个指令在单个 CPU 上交替执行 同一时间段处理多件事情的能力。一个人做多件事。
2.3线程应用
2.3.1异步调用
同步异步:
- 需要等待结果返回,才能继续运行就是同步
- 不需要等待结果返回,就能继续运行就是异步
多线程可以让方法执行变为异步的,不会干巴巴等着,比如读取磁盘要花费5秒,如果没有线程调度机制,这5秒什么事情都做不了。
视频文件要转换格式操作比较费时,可以开一个新线程处理视频转换,避免阻塞主线程。
2.3.2 提升效率

2.3.3线程应用提升效率验证和小结
- 单核 cpu 下,多线程不能实际提高程序运行效率,只是为了能够在不同的任务之间切换,不同线程轮流使用cpu ,不至于一个线程总占用 cpu,别的线程没法干活
- 多核 cpu 可以并行跑多个线程,但能否提高程序运行效率还是要分情况的
有些任务,经过精心设计,将任务拆分,并行执行,当然可以提高程序的运行效率。但不是所有计算任务都能拆分(参考后文的【阿姆达尔定律】)
也不是所有任务都需要拆分,任务的目的如果不同,谈拆分和效率没啥意义 - IO 操作不占用 cpu,只是我们一般拷贝文件使用的是【阻塞 IO】,这时相当于线程虽然不用 cpu,但需要一直等待 IO 结束,没能充分利用线程。所以才有后面的【非阻塞 IO】和【异步 IO】优化
3.Java 线程
本章内容
- 创建和运行线程
- 查看线程
- 线程 API
- 线程状态
3.1 创建和运行线程
方法一,直接使用 Thread
Thread 创建线程方式:创建线程类,匿名内部类方式
- start() 方法底层其实是给 CPU 注册当前线程,并且触发 run() 方法执行
- 线程的启动必须调用 start() 方法,如果线程直接调用 run() 方法,相当于变成了普通类的执行,此时主线程将只有执行该线程
- 建议线程先创建子线程,主线程的任务放在之后,否则主线程(main)永远是先执行完
Thread 构造器:
public Thread()public Thread(String name)
1 | // 创建线程对象 |
例如:
1 | (topic = "c.Test1") |


方法二,使用Runnable配合Thread创建线程
Runnable 创建线程方式:创建线程类,匿名内部类方式
Thread 的构造器:
public Thread(Runnable target)public Thread(Runnable target, String name)
把【线程】和【任务】(要执行的代码)分开
- Thread 代表线程
- Runnable 可运行的任务(线程要执行的代码)
1 | Runnable runnable = new Runnable() { |
例如:
1 | (topic="c.Test2") |
JDK8后可以用lambda简化
1 |
|
还可以再简化:

将任务和线程分离:


原理之 Thread 与 Runnable 的关系
1 | public class ThreadDemo { |
Thread 类本身也是实现了 Runnable 接口,Thread 类中持有 Runnable 的属性,执行线程 run 方法底层是调用 Runnable#run:
1 | public class Thread implements Runnable { |
Thread本身实现了Runnable接口。Thread中持有一个Runnable target对象。- 当我们使用
new Thread(runnable)创建线程时,真正运行的是runnable.run()。 - 若没有传入 target,则可以重写 Thread 的 run 方法。
小结
- 方法1(直接使用 Thread) 是把线程和任务合并在了一起,方法2(使用Runnable配合Thread创建线程) 是把线程和任务分开了
- 用 Runnable 更容易与线程池等高级 API 配合
- 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活
| 方法 | 描述 | 特点 |
|---|---|---|
| 方式一:继承 Thread 类 | 任务和线程绑定在一起 | 不灵活,无法复用任务 |
| 方式二:实现 Runnable 接口 | 任务与线程分离 | 更加灵活,任务可以被多个线程复用;更适合配合线程池等高级 API |
为什么推荐使用 Runnable?
- 任务解耦:Runnable 让“线程的创建”与“任务的逻辑”分离,职责更清晰。
- 复用性强:一个
Runnable实例可以被多个线程执行。 - 兼容性好:避免 Java 单继承限制,可以让任务类继承其他类。
- 线程池支持:线程池的核心工作单元就是
Runnable或Callable。
方法三,FutureTask 配合 Thread
适用场景
当你希望线程执行后能返回一个结果,就不能使用 Runnable,而应该使用 Callable + FutureTask,FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
原理说明
-
FutureTask实现了Runnable接口,所以可以被Thread执行。 -
FutureTask1
2
3
4
5
6
也是一个“任务对象”,支持:
- `run()`:用于被线程调用执行
- `get()`:用于获取线程执行完后的结果(**阻塞方法**,等待执行完毕)
public class FutureTask
private Callable
private V result;
public void run() {
result = callable.call(); // 执行任务并保存结果
}
public V get() {
// 阻塞等待任务完成并返回 result
return result;
}
}
1 |
|
@Slf4j(topic=“c.Test2”)
public class Test3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 步骤4:包装 Callable 为 FutureTask
FutureTask
@Override
public Integer call() throws Exception {
log.debug(“running…”);
Thread.sleep(2000); // 模拟耗时任务
return 100;
}
});
// 步骤5:包装为线程并启动
Thread t1 = new Thread(task, "t1");
t1.start();
// 步骤6:同步等待结果
log.debug("结果为:{}", task.get());
}
}
1 |
|
tasklist | findstr java
1 |
|
jps
1 |
|
taskkill /F /PID PID号
1 |
|
@Slf4j(topic=“c.Test7”)
public class Test6 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(“t1”) {
public void run() {
log.debug(“enter sleep…”);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
log.debug(“wake up…”);
throw new RuntimeException(e);
}
}
};
t1.start();
log.debug(“begin”);
Thread.sleep(1000);
log.debug(“interrupt”);
t1.interrupt();
}
}
1 |
|
@Slf4j(topic = “c.Test8”)
public class Test7 {
public static void main(String[] args) throws InterruptedException {
log.debug(“enter”);
TimeUnit.SECONDS.sleep(1);
log.debug(“end”);
}
}
1 |
|
@Slf4j(topic=“c.Test4”)
public class test4 {
public static void main(String[] args) {
Runnable task1 =()->{
int count=0;
for(;;){
System.out.println(“------>1”+count++);
}
};
Runnable task2 =()->{
int count=0;
for(;;){
//Thread.yield();
System.out.println(" ------>2"+count++);
}
};
Thread t1 = new Thread(task1,“t1”);
Thread t2 = new Thread(task2,“t2”);
//t1.setPriority(Thread.MIN_PRIORITY);
//t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
1 |
|
@Slf4j(topic=“c.Test5”)
public class test5 {
static int r=0;
public static void main(String[] args) throws InterruptedException{
test1();
}
public static void test1() throws InterruptedException{
log.debug("开始");
Thread t1 = new Thread(()->{
log.debug("开始");
sleep(1);
log.debug("结束");
r=10;
},"t1");
t1.start();
t1.join();
log.debug("结果为:{}",r);
log.debug("结果");
}
}
1 |
|
public final synchronized void join(long millis) throws InterruptedException {
// 调用者线程进入 thread 的 waitSet 等待, 直到当前线程运行结束
while (isAlive()) {
wait(0);
}
}
1 |
|
@Slf4j(topic = “c.TestJoin”)
public class TestJoin {
static int r = 0;
static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {
test2();
}
private static void test2() throws InterruptedException {
Thread t1 = new Thread(() -> {
sleep(1);
r1 = 10;
});
Thread t2 = new Thread(() -> {
sleep(2);
r2 = 20;
});
t1.start();
t2.start();
long start = System.currentTimeMillis();
log.debug("join begin");
t1.join();
log.debug("t1 join end");
t2.join();
log.debug("t2 join end");
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
}
1 |
|
@Slf4j(topic = “c.TestJoin”)
public class TestJoin {
static int r = 0;
static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {
test3();
}
public static void test3() throws InterruptedException {
Thread t1 = new Thread(() -> {
sleep(2);
r1 = 10;
});
long start = System.currentTimeMillis();
t1.start();
// 线程执行结束会导致 join 结束
log.debug("join begin");
t1.join(1500);
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
}
1 |
|
@Slf4j(topic=“c.Test6”)
public class test6 {
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
log.debug(“sleep…”);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, “t1”);
t1.start();
Thread.sleep(1000);
log.debug(“interrupt”);
t1.interrupt();
log.debug(“打断标记:{}”,t1.isInterrupted());//打断状态:false
}
}
1 |
|
@Slf4j(topic=“c.Test7”)
public class Test7 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
while(true){
boolean interrupted = Thread.currentThread().isInterrupted();
if(interrupted){
log.debug(“被打断了,退出循环”);
break;
}
}
},“t1”);
t1.start();
Thread.sleep(1000);
log.debug(“interrupt”);
t1.interrupt();
}
}
1 |
|
@Slf4j(topic = “c.TwoPhaseTermination”)
class TwoPhaseTermination{
private Thread monitor;
//启动监控线程
public void start(){
monitor = new Thread(()->{
while(true) {
Thread current = Thread.currentThread();
if (current.isInterrupted()) {
log.debug(“料理后事”);
break;
}
try {
Thread.sleep(1000);
log.debug(“执行监控记录”);
} catch (InterruptedException e) {
e.printStackTrace();
//重新设置打断标记
current.interrupt();
}
}
});
monitor.start();
}
//停止监控线程
public void stop(){
monitor.interrupt();
}
}
1 |
|
@Slf4j(topic=“c.Test9”)
public class java9 {
public static void main(String[] args) throws InterruptedException{
test1();
}
public static void test1() throws InterruptedException{
Thread t1 = new Thread(()->{
log.debug(“park…”);
LockSupport.park();
log.debug(“unpark…”);
log.debug(“打断状态:{}”,Thread.interrupted());
LockSupport.park();
log.debug(“unpark…”);
},“t1”);
t1.start();
sleep(1);
t1.interrupt();
}
}
1 |
|
@Slf4j(topic=“c.Test15”)
public class Test10 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
while(true){
if(Thread.currentThread().isInterrupted()){
break;
}
}
});
t1.setDaemon(true);
t1.start();
Thread.sleep(1000);
log.debug(“结束”);
}
}
1 |
|
@Slf4j(topic = “c.Test16”)
public class Test11 {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
log.debug(“洗水壶”);
Sleeper.sleep(1);
log.debug(“烧开水”);
Sleeper.sleep(5);
},“老王”);
Thread t2 = new Thread(()->{
log.debug(“洗茶壶”);
Sleeper.sleep(1);
log.debug(“洗茶杯”);
Sleeper.sleep(2);
log.debug(“拿茶叶”);
Sleeper.sleep(1);
try {
t1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(“泡茶”);
},“小王”);
t1.start();
t2.start();
}
}
1 |
|
@Slf4j(topic=“c.Test12”)
public class Test12 {
static int counter = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
counter++;
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
counter--;
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("{}", counter);
}
}
1 |
|
synchronized(对象){
临界区
}
1 |
|
@Slf4j(topic=“c.Test12”)
public class Test12 {
static int counter = 0;
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock){
counter++;
}
}
}, “t1”);
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock){
counter–;
}
}
}, “t2”);
t1.start();
t2.start();
t1.join();
t2.join();
log.debug(“{}”, counter);
}
}
1 |
|
@Slf4j(topic=“c.Test12”)
public class Test12 {
public static void main(String[] args) throws InterruptedException {
Room room = new Room();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (room){
room.increment();
}
}
}, “t1”);
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (room){
room.decrement();
}
}
}, “t2”);
t1.start();
t2.start();
t1.join();
t2.join();
log.debug(“{}”, room.getCounter());
}
}
class Room{
private int counter = 0;
public void increment(){
synchronized (this){
counter++;
}
}
public void decrement(){
synchronized (this){
counter–;
}
}
public int getCounter(){
synchronized (this){
return counter;
}
}
}
1 |
|
public static void test1() {
int i = 10;
i++;
}
1 |
|
class ThreadUnsafe {
ArrayList
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2(); // 添加
method3(); // 删除
}
}
private void method2() {
list.add("1");
}
private void method3() {
list.remove(0);
}
}
1 |
|
Exception in thread “Thread1” java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.remove(ArrayList.java:496)
at cn.itcast.n6.ThreadUnsafe.method3(TestThreadSafe.java:35)
at cn.itcast.n6.ThreadUnsafe.method1(TestThreadSafe.java:26)
at cn.itcast.n6.TestThreadSafe.lambda$main$0(TestThreadSafe.java:14)
at java.lang.Thread.run(Thread.java:748)
1 |
|
class ThreadSafe {
public final void method1(int loopNumber) {
ArrayList
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
private void method2(ArrayList<String> list) {
list.add("1");
}
private void method3(ArrayList<String> list) {
list.remove(0);
}
}
1 |
|
class ThreadSafeSubClass extends ThreadSafe {
@Override
public void method3(ArrayList
new Thread(() -> {
list.remove(0); // 在新线程中操作原 list,可能与其它线程冲突
}).start();
}
}
1 |
|
Hashtable table = new Hashtable();
new Thread(()->{
table.put(“key”, “value1”);
}).start();
new Thread(()->{
table.put(“key”, “value2”);
}).start();
1 |
|
public class Immutable{
private int value = 0;
public Immutable(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
public Immutable add(int v){
return new Immutable(this.value + v);
}
}
1 |
|
public class MyServlet extends HttpServlet {
// 是否安全?
Map<String,Object> map = new HashMap<>();
// 是否安全?
String S1 = “…”;
// 是否安全?
final String S2 = “…”;
// 是否安全?
Date D1 = new Date();
// 是否安全?
final Date D2 = new Date();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
// 使用上述变量
}
}
1 |
|
public class MyServlet extends HttpServlet {
// 是否安全?
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 记录调用次数
private int count = 0;
public void update() {
// ...
count++;
}
}
1 |
|
@Aspect
@Component
public class MyAspect {
// 是否安全?
private long start = 0L;
@Before("execution(* *(..))")
public void before() {
start = System.nanoTime();// 被共享
}
@After("execution(* *(..))")
public void after() {
long end = System.nanoTime();
System.out.println("cost time:" + (end-start));// 可能混淆
}
}
1 |
|
public class MyServlet extends HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 是否安全
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
public void update() {
String sql = “update user set password = ? where username = ?”;
// 是否安全
try (Connection conn = DriverManager.getConnection(“”,“”,“”)){
// …
} catch (Exception e) {
// …
}
}
}
1 |
|
private Connection conn = null;
public void update() {
conn = DriverManager.getConnection(…);
}
1 |
|
public class UserServiceImpl implements UserService {
public void update() {
UserDao userDao = new UserDaoImpl();
userDao.update();
}
}
1 |
|
public void bar() {
SimpleDateFormat sdf = new SimpleDateFormat(…);
foo(sdf); // 将可变对象传出
}
public void foo(SimpleDateFormat sdf) {
// 多线程并发使用 sdf ➜ 非线程安全
}
1 |
|
synchronized (i) {
i++; // ❌ 实际上每次 i++ 后 i 对象地址发生变化,锁定无效
}
1 |
|
@Slf4j(topic=“c.ExerciseSell”)
public class ExerciseTransfer {
public static void main(String[] args) throws InterruptedException {
//模拟多人买票
TicketWindow window = new TicketWindow(100000);
//所有线程的集合
List
//卖出的票数统计
List
for(int i=0;i<20000;i++){
Thread thread = new Thread(()->{
int amount = window.sell(randomAmount());//买票
try {
Thread.sleep(randomAmount());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
amountList.add(amount);
});
threadList.add(thread);
thread.start();
}
for (Thread thread :threadList) {
thread.join();
}
log.debug(“余票:{}”,window.getCount());
log.debug(“卖出的票数:{}”,amountList.stream().mapToInt(i->i).sum());
}
static Random random = new Random();
public static int randomAmount(){
return random.nextInt(5)+1;
}
}
class TicketWindow{
private int count;
public TicketWindow(int count){
this.count = count;
}
public int getCount(){
return count;
}
public int sell(int amount){
if(this.count >= amount){
this.count -= amount;
return amount;
}else{
return 0;
}
}
}
1 |
|
List
1 |
|
@Slf4j(topic=“c.ExerciseTransfer”)
public class ExerciseTransfer1{
public static void main(String[] args) throws InterruptedException {
Account a = new Account(1000);
Account b = new Account(1000);
Thread t1 = new Thread(()->{
for (int i = 0; i < 1000; i++) {
a.transfer(b,randomAmount());
}
},“t1”);
Thread t2 = new Thread(()->{
for (int i = 0; i < 1000; i++) {
b.transfer(a,randomAmount());
}
},“t2”);
t1.start();
t2.start();
t1.join();
t2.join();
log.debug(“total:{}”,(a.getMoney()+b.getMoney()));
}
static Random random = new Random();
public static int randomAmount(){return random.nextInt(100)+1;}
}
class Account {
private int money;
public Account(int money){
this.money = money;
}
public int getMoney(){
return money;
}
public void setMoney(int money){
this.money = money;
}
public void transfer(Account target,int amount){
synchronized(Account.class) {
if (this.money >= amount) {
this.setMoney(this.getMoney() - amount);//自身余额,减去转账金额
target.setMoney(target.getMoney() + amount);//对方余额加上转账金额
}
}
}
}
1 |
|
static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
synchronized (lock) {
counter++;
}
}
1 |
|
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: getstatic #2 // // 获取 lock 对象
3: dup
4: astore_1 // lock引用 -> slot 1
5: monitorenter // 加锁:将 MarkWord 设为 Monitor 指针
6: getstatic #3 // <- i
9: iconst_1 // 准备常数 1
10: iadd // +1
11: putstatic #3 // -> i
14: aload_1 // // 解锁
15: monitorexit // 将 lock对象 MarkWord 重置, 唤醒 EntryList
16: goto 24
19: astore_2 // 异常处理,存异常到 slot
20: aload_1 // <- lock引用
21: monitorexit // 异常时也要解锁
22: aload_2 // <- slot 2 (e)
23: athrow // 抛出异常
24: return
Exception table:
from to target type
6 16 19 any
19 22 19 any
LineNumberTable:
line 8: 0
line 9: 6
line 10: 14
line 11: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 args [Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame /
offset_delta = 19
locals = [ class “[Ljava/lang/String;”, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 / chop */
offset_delta = 4
1 |
|
static final Object obj = new Object();
public static void method1() {
synchronized( obj ) {
// 同步块 A
method2();
}
}
public static void method2() {
synchronized( obj ) {
// 同步块 B
}
}
1 |
|
无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 // 随着竞争的增加,只能锁升级,不能降级
1 |
|
static final Object obj = new Object();
public static void method1() {
synchronized(obj) {
// 同步块
}
}
1 |
|
public static void m1() {
synchronized(obj) { m2(); }
}
public static void m2() {
synchronized(obj) { m3(); }
}
public static void m3() {
synchronized(obj) { }
}
1 |
|
Dog d = new Dog();
synchronized (d) {
// 查看对象的 Mark Word
}
1 |
|
public class TestBiased1 {
static final int LOOP_NUMBER = 39;
public static void main(String[] args) throws InterruptedException {
ArrayList<Dog> list = new ArrayList<>();
Thread t1 = new Thread(() -> {
for (int i = 0; i < LOOP_NUMBER; i++) {
Dog dog = new Dog();
list.add(dog);
synchronized (dog) {}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < LOOP_NUMBER; i++) {
Dog dog = list.get(i);
synchronized (dog) {
// 这里触发 rebias
}
}
});
t1.start(); t1.join();
t2.start(); t2.join();
}
}
1 |
|
public class TestBiased2 {
static final int LOOP_NUMBER = 41;
public static void main(String[] args) throws InterruptedException {
ArrayList<Dog> list = new ArrayList<>();
Thread t1 = new Thread(() -> {
for (int i = 0; i < LOOP_NUMBER; i++) {
Dog dog = new Dog();
list.add(dog);
synchronized (dog) {}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < LOOP_NUMBER; i++) {
Dog dog = list.get(i);
synchronized (dog) {}
}
});
t1.start(); t1.join();
t2.start(); t2.join();
}
}
1 |
|
@Slf4j(topic = “c.TestWaitNotify”)
public class TestWaitNotify {
final static Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug(“执行…”);
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(“其它代码…”);
}
},“t2”).start();
new Thread(() -> {
synchronized (obj) {
log.debug(“执行…”);
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(“其它代码…”);
}
},“t1”).start();
// 主线程两秒后执行
sleep(0.5);
log.debug(“唤醒 obj 上其它线程”);
synchronized (obj) {
//obj.notify(); // 唤醒obj上一个线程
obj.notifyAll(); // 唤醒obj上所有等待线程
}
}
}
1 |
|
@Slf4j(topic=“c.Test19”)
public class Test14 {
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (lock) {
log.debug("获得锁");
try {
Thread.sleep(10000);
//lock.wait(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1").start();
Sleeper.sleep(1);
synchronized (lock){
log.debug("获得锁");
}
}
}
1 |
|
new Thread(() -> {
synchronized (room) {
log.debug(“有烟没?[{}]”, hasCigarette);
if (!hasCigarette) {
log.debug(“没烟,先歇会!”);
sleep(2);
}
log.debug(“有烟没?[{}]”, hasCigarette);
if (hasCigarette) {
log.debug(“可以开始干活了”);
}
}
}, “小南”).start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
synchronized (room) {
log.debug(“可以开始干活了”);
}
}, “其它人”).start();
}
sleep(1);
new Thread(() -> {
// 这里能不能加 synchronized (room)?
hasCigarette = true;
log.debug(“烟到了噢!”);
}, “送烟的”).start();
1 |
|
new Thread(() -> {
synchronized (room) {
log.debug(“有烟没?[{}]”, hasCigarette);
if (!hasCigarette) {
log.debug(“没烟,先歇会!”);
try {
room.wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(“有烟没?[{}]”, hasCigarette);
if (hasCigarette) {
log.debug(“可以开始干活了”);
}
}
}, “小南”).start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
synchronized (room) {
log.debug(“可以开始干活了”);
}
}, “其它人”).start();
}
sleep(1);
new Thread(() -> {
synchronized (room) {
hasCigarette = true;
log.debug(“烟到了噢!”);
room.notify();
}
}, “送烟的”).start();
1 |
|
new Thread(() -> {
synchronized (room) {
log.debug(“有烟没?[{}]”, hasCigarette);
if (!hasCigarette) {
log.debug(“没烟,先歇会!”);
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(“有烟没?[{}]”, hasCigarette);
if (hasCigarette) {
log.debug(“可以开始干活了”);
} else {
log.debug(“没干成活…”);
}
}
}, “小南”).start();
new Thread(() -> {
synchronized (room) {
Thread thread = Thread.currentThread();
log.debug(“外卖送到没?[{}]”, hasTakeout);
if (!hasTakeout) {
log.debug(“没外卖,先歇会!”);
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(“外卖送到没?[{}]”, hasTakeout);
if (hasTakeout) {
log.debug(“可以开始干活了”);
} else {
log.debug(“没干成活…”);
}
}
}, “小女”).start();
sleep(1);
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug(“外卖到了噢!”);
room.notify();
}
}, “送外卖的”).start();
1 |
|
20:53:12.173 [小南] c.TestCorrectPosture - 有烟没?[false]
20:53:12.176 [小南] c.TestCorrectPosture - 没烟,先歇会!
20:53:12.176 [小女] c.TestCorrectPosture - 外卖送到没?[false]
20:53:12.176 [小女] c.TestCorrectPosture - 没外卖,先歇会!
20:53:13.174 [送外卖的] c.TestCorrectPosture - 外卖到了噢!
20:53:13.174 [小南] c.TestCorrectPosture - 有烟没?[false]
20:53:13.174 [小南] c.TestCorrectPosture - 没干成活…
1 |
|
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug(“外卖到了噢!”);
room.notifyAll();
}
}, “送外卖的”).start();
1 |
|
20:55:23.978 [小南] c.TestCorrectPosture - 有烟没?[false]
20:55:23.982 [小南] c.TestCorrectPosture - 没烟,先歇会!
20:55:23.982 [小女] c.TestCorrectPosture - 外卖送到没?[false]
20:55:23.982 [小女] c.TestCorrectPosture - 没外卖,先歇会!
20:55:24.979 [送外卖的] c.TestCorrectPosture - 外卖到了噢!
20:55:24.979 [小女] c.TestCorrectPosture - 外卖送到没?[true]
20:55:24.980 [小女] c.TestCorrectPosture - 可以开始干活了
20:55:24.980 [小南] c.TestCorrectPosture - 有烟没?[false]
20:55:24.980 [小南] c.TestCorrectPosture - 没干成活…
1 |
|
if (!hasCigarette) {
log.debug(“没烟,先歇会!”);
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1 |
|
while (!hasCigarette) {
log.debug(“没烟,先歇会!”);
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1 |
|
20:58:34.322 [小南] c.TestCorrectPosture - 有烟没?[false]
20:58:34.326 [小南] c.TestCorrectPosture - 没烟,先歇会!
20:58:34.326 [小女] c.TestCorrectPosture - 外卖送到没?[false]
20:58:34.326 [小女] c.TestCorrectPosture - 没外卖,先歇会!
20:58:35.323 [送外卖的] c.TestCorrectPosture - 外卖到了噢!
20:58:35.324 [小女] c.TestCorrectPosture - 外卖送到没?[true]
20:58:35.324 [小女] c.TestCorrectPosture - 可以开始干活了
20:58:35.324 [小南] c.TestCorrectPosture - 没烟,先歇会!
synchronized(lock) {
while(条件不成立) {
lock.wait();
}
// 干活
}
//另一个线程
synchronized(lock) {
lock.notifyAll();
}
1 |
|
@Slf4j(topic = “c.Test20”)
public class Test15 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
//等待结果
log.debug(“等待结果”);
List
log.debug(“结果大小:{}”,list.size());
},“t1”).start();
new Thread(()->{
log.debug(“执行下载”);
try {
List
guardedObject.complete(list);
} catch (IOException e) {
throw new RuntimeException(e);
}
},“t2”).start();
}
}
class GuardedObject{
//结果
private Object response;
//获取结果
public Object get(){
synchronized (this){
while(response==null){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return response;
}
}
//产生结果
public void complete(Object response){
synchronized (this){
//给结果成员变量赋值
this.response = response;
this.notifyAll();
}
}
}
1 |
|
public Object get(long timeout){
synchronized (this){
//开始时间
long begin = System.currentTimeMillis();
//经历的时间
long passedTime = 0;
while(response==null){
//经历的时间超过最大等待时间,退出循环
if(passedTime>=timeout){
break;
}
try {
this.wait(timeout-passedTime);//防止虚假唤醒,唤醒之后结果数据还没准备好。
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//求得经历时间
passedTime = System.currentTimeMillis() - begin;
}
return response;
}
}
1 |
|
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
log.debug(“begin”);
Object response = guardedObject.get(2000);
log.debug(“结果是:{}”,response);
},“t1”).start();
new Thread(()->{
log.debug(“begin”);
Sleeper.sleep(1);
guardedObject.complete(null);
},“t2”).start();
}
1 |
|
t1.join();
1 |
|
synchronized (t1) {
// 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
while (t1.isAlive()) {
t1.wait(0);
}
}
1 |
|
//不带参
public final void join() throws InterruptedException {
join(0);
}
//带参
//等待时长的实现类似于之前的保护性暂停
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
1 |
|
Map<Integer, GuardedObject> boxes
1 |
|
@Slf4j(topic = “c.Test20”)
public class Test15 {
public static void main(String[] args) {
for(int i=0;i<3;i++){
new People().start();
}
Sleeper.sleep(1);
for(Integer id : Mailboxes.getIds()){
new Postman(id,"内容"+id).start();
}
}
}
@Slf4j(topic=“c.People”)
class People extends Thread{
@Override
public void run() {
//收信
GuardedObject guardedObject = Mailboxes.createGuardedObject();
log.debug(“开始收信 id:{}”,guardedObject.getId());
Object mail = guardedObject.get(5000);
log.debug(“收到信 id:{} , 内容:{}”,guardedObject.getId(),mail);
}
}
@Slf4j(topic=“c.Postman”)
class Postman extends Thread{
private int id;
private String mail;
public Postman(int id,String mail){
this.id = id;
this.mail = mail;
}
@Override
public void run() {
GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
log.debug(“开始收信 id:{},内容:{}”,id,mail);
guardedObject.complete(mail);
}
}
class Mailboxes{
private static Map<Integer,GuardedObject> boxes = new Hashtable<>();
private static int id = 1;
//产生唯一id
private static synchronized int generateId(){
return id++;
}
public static GuardedObject getGuardedObject(int id){
return boxes.remove(id);
}
public static GuardedObject createGuardedObject(){
GuardedObject go = new GuardedObject(generateId());
boxes.put(go.getId(),go);
return go;
}
public static Set<Integer> getIds(){
return boxes.keySet();
}
}
class GuardedObject{
private int id;
public GuardedObject(int id){
this.id = id;
}
public int getId(){
return id;
}
//结果
private Object response;
//获取结果
public Object get(long timeout){
synchronized (this){
//开始时间
long begin = System.currentTimeMillis();
//经历的时间
long passedTime = 0;
while(response==null){
//经历的时间超过最大等待时间,退出循环
if(passedTime>=timeout){
break;
}
try {
this.wait(timeout-passedTime);//防止虚假唤醒,唤醒之后结果数据还没准备好。
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//求得经历时间
passedTime = System.currentTimeMillis() - begin;
}
return response;
}
}
//产生结果
public void complete(Object response){
synchronized (this){
//给结果成员变量赋值
this.response = response;
this.notifyAll();
}
}
}
1 |
|
@Slf4j(topic = “c.Test21”)
public class Test16 {
public static void main(String[] args) {
MessageQueue queue = new MessageQueue(2);
for (int i = 0; i < 3; i++) {
int id = i;
new Thread(()->{
queue.put(new Message(id,“值”+id));
},“生产者”+i).start();
}
new Thread(()->{
while(true) {
sleep(1);
Message message = queue.take();
}
},“消费者”).start();
}
}
@Slf4j(topic = “c.MessageQueue”)
class MessageQueue{
//消息的队列集合
private LinkedList
//队列容量
private int capcity;
public MessageQueue(int capcity){
this.capcity=capcity;
}
//获取消息
public Message take(){
//检查队列是否为空
synchronized (list) {
while (list.isEmpty()) {
try {
log.debug("队列为空,消费者线程等待");
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//从队列头部获取消息返回。
Message message = list.removeFirst();
log.debug("已消费消息{}",message);
list.notifyAll();
return message;
}
}
//存入消息
public void put(Message message){
synchronized (list){
//检查队列是否已满
while(list.size()==capcity){
try {
log.debug("队列为满,生产者线程等待");
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//将消息加入队列尾部
list.addLast(message);
log.debug("已生产消息{}",message);
list.notifyAll();
}
}
}
final class Message{
private int id;
private Object value;
public Message(int id,Object value){
this.id=id;
this.value=value;
}
public int getId(){
return id;
}
public Object getValue(){
return value;
}
@Override
public String toString() {
return "Message{" +
"id=" + id +
", value=" + value +
'}';
}
}
1 |
|
// 暂停当前线程
LockSupport.park();
// 恢复某个线程的运行
LockSupport.unpark(暂停线程对象)
1 |
|
Thread t1 = new Thread(() -> {
log.debug(“start…”);
sleep(1);
log.debug(“park…”);
LockSupport.park();
log.debug(“resume…”);
},“t1”);
t1.start();
sleep(2);
log.debug(“unpark…”);
LockSupport.unpark(t1);
1 |
|
18:42:52.585 c.TestParkUnpark [t1] - start…
18:42:53.589 c.TestParkUnpark [t1] - park…
18:42:54.583 c.TestParkUnpark [main] - unpark…
18:42:54.583 c.TestParkUnpark [t1] - resume…
1 |
|
Thread t1 = new Thread(() -> {
log.debug(“start…”);
sleep(2);
log.debug(“park…”);
LockSupport.park();
log.debug(“resume…”);
}, “t1”);
t1.start();
sleep(1);
log.debug(“unpark…”);
LockSupport.unpark(t1);
1 |
|
18:43:50.765 c.TestParkUnpark [t1] - start…
18:43:51.764 c.TestParkUnpark [main] - unpark…
18:43:52.769 c.TestParkUnpark [t1] - park…
18:43:52.769 c.TestParkUnpark [t1] - resume…
1 |
|
Thread t = new Thread();
t.start();
1 |
|
synchronized(obj) {
obj.wait(); // RUNNABLE → WAITING
}
1 |
|
obj.notify()
1 |
|
obj.notifyAll()
1 |
|
t.interrupt()
1 |
|
public class TestWaitNotify {
final static Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug(“执行…”);
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(“其它代码…”); // 断点
}
},“t1”).start();
new Thread(() -> {
synchronized (obj) {
log.debug(“执行…”);
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(“其它代码…”); // 断点
}
},“t2”).start();
sleep(0.5);
log.debug("唤醒 obj 上其它线程");
synchronized (obj) {
obj.notifyAll(); // 唤醒obj上所有等待线程 断点
}
}
}
1 |
|
Thread t1, t2 在 obj 上 wait();
main 线程唤醒所有等待线程:
synchronized(obj) {
obj.notifyAll();
}
1 |
|
t.join();
1 |
|
LockSupport.park();
LockSupport.unpark(t);
1 |
|
obj.wait(n);//等待最多n秒后恢复。
1 |
|
obj.notify()
1 |
|
obj.notifyAll()
1 |
|
t.interrupt()
1 |
|
t.join(1000);//当前线程等待目标线程最多 1 秒。
1 |
|
Thread.sleep(1000);
1 |
|
LockSupport.parkNanos(1000_000);
1 |
|
synchronized(obj) {
// 抢锁失败 → BLOCKED
}
1 |
|
@Override
public void run() {
// 执行完所有代码后自动进入 TERMINATED
}
1 |
|
public void sleep() {
synchronized (this) { … }
}
public void study() {
synchronized (this) { … }
}
1 |
|
12:13:54.471 [小南] study 1 小时
12:13:55.476 [小女] sleeping 2 小时
1 |
|
private final Object studyRoom = new Object();
private final Object bedRoom = new Object();
public void study() {
synchronized (studyRoom) { … }
}
public void sleep() {
synchronized (bedRoom) { … }
}
1 |
|
12:15:35.069 [小南] study 1 小时
12:15:35.069 [小女] sleeping 2 小时
1 |
|
Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized (A) {
log.debug(“lock A”);
sleep(1);
synchronized (B) {
log.debug(“lock B”);
log.debug(“操作…”);
}
}
}, “t1”);
Thread t2 = new Thread(() -> {
synchronized (B) {
log.debug(“lock B”);
sleep(0.5);
synchronized (A) {
log.debug(“lock A”);
log.debug(“操作…”);
}
}
}, “t2”);
t1.start();
t2.start();
1 |
|
cmd > jps
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
12320 Jps
22816 KotlinCompileDaemon
33200 TestDeadLock // JVM 进程
11508 Main
28468 Launcher
cmd > jstack 33200
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
2018-12-29 05:51:40
Full thread dump Java HotSpot™ 64-Bit Server VM (25.91-b14 mixed mode):
“DestroyJavaVM” #13 prio=5 os_prio=0 tid=0x0000000003525000 nid=0x2f60 waiting on condition
[0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“Thread-1” #12 prio=5 os_prio=0 tid=0x000000001eb69000 nid=0xd40 waiting for monitor entry
[0x000000001f54f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at thread.TestDeadLock.lambda$main$1(TestDeadLock.java:28)
- waiting to lock <0x000000076b5bf1c0> (a java.lang.Object)
- locked <0x000000076b5bf1d0> (a java.lang.Object)
at thread.TestDeadLock$$Lambda$2/883049899.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
“Thread-0” #11 prio=5 os_prio=0 tid=0x000000001eb68800 nid=0x1b28 waiting for monitor entry
[0x000000001f44f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at thread.TestDeadLock.lambda$main$0(TestDeadLock.java:15)
- waiting to lock <0x000000076b5bf1d0> (a java.lang.Object)
- locked <0x000000076b5bf1c0> (a java.lang.Object)
at thread.TestDeadLock$$Lambda$1/495053715.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
// 略去部分输出
Found one Java-level deadlock:
“Thread-1”:
waiting to lock monitor 0x000000000361d378 (object 0x000000076b5bf1c0, a java.lang.Object),
which is held by “Thread-0”
“Thread-0”:
waiting to lock monitor 0x000000000361e768 (object 0x000000076b5bf1d0, a java.lang.Object),
which is held by “Thread-1”
Java stack information for the threads listed above:
“Thread-1”:
at thread.TestDeadLock.lambda$main$1(TestDeadLock.java:28)
- waiting to lock <0x000000076b5bf1c0> (a java.lang.Object)
- locked <0x000000076b5bf1d0> (a java.lang.Object)
at thread.TestDeadLock$$Lambda$2/883049899.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
“Thread-0”:
at thread.TestDeadLock.lambda$main$0(TestDeadLock.java:15)
- waiting to lock <0x000000076b5bf1d0> (a java.lang.Object)
- locked <0x000000076b5bf1c0> (a java.lang.Object)
at thread.TestDeadLock$$Lambda$1/495053715.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
1 |
|
class Chopstick {
String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return “筷子{” + name + ‘}’;
}
}
1 |
|
class Philosopher extends Thread {
Chopstick left;
Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);
this.left = left;
this.right = right;
}
private void eat() {
log.debug(“eating…”);
Sleeper.sleep(1);
}
@Override
public void run() {
while (true) {
// 获得左手筷子
synchronized (left) {
// 获得右手筷子
synchronized (right) {
// 吃饭
eat();
}
// 放下右手筷子
}
// 放下左手筷子
}
}
}
1 |
|
Chopstick c1 = new Chopstick(“1”);
Chopstick c2 = new Chopstick(“2”);
Chopstick c3 = new Chopstick(“3”);
Chopstick c4 = new Chopstick(“4”);
Chopstick c5 = new Chopstick(“5”);
new Philosopher(“苏格拉底”, c1, c2).start();
new Philosopher(“柏拉图”, c2, c3).start();
new Philosopher(“亚里士多德”, c3, c4).start();
new Philosopher(“赫拉克利特”, c4, c5).start();
new Philosopher(“阿基米德”, c5, c1).start();
1 |
|
public class TestLiveLock {
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
// 期望减到 0 退出循环
while (count > 0) {
sleep(0.2);
count–;
log.debug(“count: {}”, count);
}
}, “t1”).start();
new Thread(() -> {
// 期望超过 20 退出循环
while (count < 20) {
sleep(0.2);
count++;
log.debug(“count: {}”, count);
}
}, “t2”).start();
}
}
1 |
|
// t1希望 count 减到 0 退出
// t2希望 count 增到 20 退出
1 |
|
// 引入随机睡眠时间
sleep((long)(Math.random() * 500));
1 |
|
// 获取锁
reentrantLock.lock();
try {
// 临界区
} finally {
// 释放锁
reentrantLock.unlock();
}
1 |
|
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
method1();
}
public static void method1() {
lock.lock();
try {
log.debug(“execute method1”);
method2();
} finally {
lock.unlock();
}
}
public static void method2() {
lock.lock();
try {
log.debug(“execute method2”);
method3();
} finally {
lock.unlock();
}
}
public static void method3() {
lock.lock();
try {
log.debug(“execute method3”);
} finally {
lock.unlock();
}
}
1 |
|
17:59:11.862 [main] c.TestReentrant - execute method1
17:59:11.865 [main] c.TestReentrant - execute method2
17:59:11.865 [main] c.TestReentrant - execute method3
1 |
|
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug(“启动…”);
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
log.debug(“等锁的过程中被打断”);
return;
}
try {
log.debug(“获得了锁”);
} finally {
lock.unlock();
}
}, “t1”);
lock.lock();
log.debug(“获得了锁”);
t1.start();
try {
sleep(1);
t1.interrupt();
log.debug(“执行打断”);
} finally {
lock.unlock();
}
1 |
|
18:02:40.520 [main] c.TestInterrupt - 获得了锁
18:02:40.524 [t1] c.TestInterrupt - 启动…
18:02:41.530 [main] c.TestInterrupt - 执行打断
java.lang.InterruptedException
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchr
onizer.java:898)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchron
izer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at cn.itcast.n4.reentrant.TestInterrupt.lambda$main$0(TestInterrupt.java:17)
at java.lang.Thread.run(Thread.java:748)
18:02:41.532 [t1] c.TestInterrupt - 等锁的过程中被打断
1 |
|
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug(“启动…”);
lock.lock();
try {
log.debug(“获得了锁”);
} finally {
lock.unlock();
}
}, “t1”);
lock.lock();
log.debug(“获得了锁”);
t1.start();
try {
sleep(1);
t1.interrupt();
log.debug(“执行打断”);
sleep(1);
} finally {
log.debug(“释放了锁”);
lock.unlock();
}
1 |
|
18:06:56.261 [main] c.TestInterrupt - 获得了锁
18:06:56.265 [t1] c.TestInterrupt - 启动…
18:06:57.266 [main] c.TestInterrupt - 执行打断 // 这时 t1 并没有被真正打断, 而是仍继续等待锁
18:06:58.267 [main] c.TestInterrupt - 释放了锁
18:06:58.267 [t1] c.TestInterrupt - 获得了锁
1 |
|
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug(“启动…”);
if (!lock.tryLock()) {
log.debug(“获取立刻失败,返回”);
return;
}
try {
log.debug(“获得了锁”);
} finally {
lock.unlock();
}
}, “t1”);
lock.lock();
log.debug(“获得了锁”);
t1.start();
try {
sleep(2);
} finally {
lock.unlock();
}
1 |
|
18:15:02.918 [main] c.TestTimeout - 获得了锁
18:15:02.921 [t1] c.TestTimeout - 启动…
18:15:02.921 [t1] c.TestTimeout - 获取立刻失败,返回
1 |
|
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug(“启动…”);
try {
if (!lock.tryLock(1, TimeUnit.SECONDS)) {
log.debug(“获取等待 1s 后失败,返回”);
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
log.debug(“获得了锁”);
} finally {
lock.unlock();
}
}, “t1”);
lock.lock();
log.debug(“获得了锁”);
t1.start();
try {
sleep(2);
} finally {
lock.unlock();
}
1 |
|
18:19:40.537 [main] c.TestTimeout - 获得了锁
18:19:40.544 [t1] c.TestTimeout - 启动…
18:19:41.547 [t1] c.TestTimeout - 获取等待 1s 后失败,返回
1 |
|
class Chopstick extends ReentrantLock {
String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return “筷子{” + name + ‘}’;
}
}
class Philosopher extends Thread {
Chopstick left;
Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);
this.left = left;
this.right = right;
}
@Override
public void run() {
while (true) {
// 尝试获得左手筷子
if (left.tryLock()) {
try {
// 尝试获得右手筷子
if (right.tryLock()) {
try {
eat();
} finally {
right.unlock();
}
}
} finally {
left.unlock();
}
}
}
}
private void eat() {
log.debug(“eating…”);
Sleeper.sleep(1);
}
}
1 |
|
ReentrantLock lock = new ReentrantLock(false);
lock.lock();
for (int i = 0; i < 500; i++) {
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " running…“);
} finally {
lock.unlock();
}
}, “t” + i).start();
}
// 1s 之后去争抢锁
Thread.sleep(1000);
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " start…”);
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " running…");
} finally {
lock.unlock();
}
}, “强行插入”).start();
lock.unlock();
1 |
|
t39 running…
t40 running…
t41 running…
t42 running…
t43 running…
强行插入 start…
强行插入 running…
t44 running…
t45 running…
t46 running…
t47 running…
t49 running…
1 |
|
ReentrantLock lock = new ReentrantLock(true);
1 |
|
t465 running…
t464 running…
t477 running…
t442 running…
t468 running…
t493 running…
t482 running…
t485 running…
t481 running…
强行插入 running…
1 |
|
static ReentrantLock lock = new ReentrantLock();
static Condition waitCigaretteQueue = lock.newCondition();
static Condition waitbreakfastQueue = lock.newCondition();
static volatile boolean hasCigrette = false;
static volatile boolean hasBreakfast = false;
public static void main(String[] args) {
new Thread(() -> {
try {
lock.lock();
while (!hasCigrette) {
try {
waitCigaretteQueue.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(“等到了它的烟”);
} finally {
lock.unlock();
}
}).start();
new Thread(() -> {
try {
lock.lock();
while (!hasBreakfast) {
try {
waitbreakfastQueue.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug(“等到了它的早餐”);
} finally {
lock.unlock();
}
}).start();
sleep(1);
sendBreakfast();
sleep(1);
sendCigarette();
}
private static void sendCigarette() {
lock.lock();
try {
log.debug(“送烟来了”);
hasCigrette = true;
waitCigaretteQueue.signal();
} finally {
lock.unlock();
}
}
private static void sendBreakfast() {
lock.lock();
try {
log.debug(“送早餐来了”);
hasBreakfast = true;
waitbreakfastQueue.signal();
} finally {
lock.unlock();
}
}
1 |
|
18:52:27.680 [main] c.TestCondition - 送早餐来了
18:52:27.682 [Thread-1] c.TestCondition - 等到了它的早餐
18:52:28.683 [main] c.TestCondition - 送烟来了
18:52:28.683 [Thread-0] c.TestCondition - 等到了它的烟
1 |
|
// 用来同步的对象
static Object obj = new Object();
// t2 运行标记, 代表 t2 是否执行过
static boolean t2runed = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (obj) {
// 如果 t2 没有执行过
while (!t2runed) {
try {
// t1 先等一会
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(1);
});
Thread t2 = new Thread(() -> {
System.out.println(2);
synchronized (obj) {
// 修改运行标记
t2runed = true;
// 通知 obj 上等待的线程(可能有多个,因此需要用 notifyAll)
obj.notifyAll();
}
});
t1.start();
t2.start();
}
1 |
|
Thread t1 = new Thread(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
// 当没有『许可』时,当前线程暂停运行;有『许可』时,用掉这个『许可』,当前线程恢复运行
LockSupport.park();// 等待“通行证”
System.out.println(“1”);
});
Thread t2 = new Thread(() -> {
System.out.println(“2”);
// 给线程 t1 发放『许可』(多次连续调用 unpark 只会发放一个『许可』)
LockSupport.unpark(t1);// 发放“通行证”
});
t1.start();
t2.start();
1 |
|
class SyncWaitNotify {
private int flag;
private int loopNumber;
public SyncWaitNotify(int flag, int loopNumber) {
this.flag = flag;
this.loopNumber = loopNumber;
}
public void print(int waitFlag, int nextFlag, String str) {
for (int i = 0; i < loopNumber; i++) {
synchronized (this) {
while (this.flag != waitFlag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(str);
flag = nextFlag;
this.notifyAll();
}
}
}
}
SyncWaitNotify syncWaitNotify = new SyncWaitNotify(1, 5);
new Thread(() -> {
syncWaitNotify.print(1, 2, “a”);
}).start();
new Thread(() -> {
syncWaitNotify.print(2, 3, “b”);
}).start();
new Thread(() -> {
syncWaitNotify.print(3, 1, “c”);
}).start();
1 |
|
class AwaitSignal extends ReentrantLock {
public void start(Condition first) {
this.lock();
try {
log.debug(“start”);
first.signal();
} finally {
this.unlock();
}
}
public void print(String str, Condition current, Condition next) {
for (int i = 0; i < loopNumber; i++) {
this.lock();
try {
current.await();
log.debug(str);
next.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.unlock();
}
}
}
// 循环次数
private int loopNumber;
public AwaitSignal(int loopNumber) {
this.loopNumber = loopNumber;
}
}
AwaitSignal as = new AwaitSignal(5);
Condition aWaitSet = as.newCondition();
Condition bWaitSet = as.newCondition();
Condition cWaitSet = as.newCondition();
new Thread(() -> {
as.print(“a”, aWaitSet, bWaitSet);
}).start();
new Thread(() -> {
as.print(“b”, bWaitSet, cWaitSet);
}).start();
new Thread(() -> {
as.print(“c”, cWaitSet, aWaitSet);
}).start();
as.start(aWaitSet);
1 |
|
class SyncPark {
private int loopNumber;
private Thread[] threads;
public SyncPark(int loopNumber) {
this.loopNumber = loopNumber;
}
public void setThreads(Thread… threads) {
this.threads = threads;
}
public void print(String str) {
for (int i = 0; i < loopNumber; i++) {
LockSupport.park();
System.out.print(str);
LockSupport.unpark(nextThread());
}
}
private Thread nextThread() {
Thread current = Thread.currentThread();
int index = 0;
for (int i = 0; i < threads.length; i++) {
if(threads[i] == current) {
index = i;
break;
}
}
if(index < threads.length - 1) {
return threads[index+1];
} else {
return threads[0];
}
}
public void start() {
for (Thread thread : threads) {
thread.start();
}
LockSupport.unpark(threads[0]);
}
}
SyncPark syncPark = new SyncPark(5);
Thread t1 = new Thread(() -> {
syncPark.print(“a”);
});
Thread t2 = new Thread(() -> {
syncPark.print(“b”);
});
Thread t3 = new Thread(() -> {
syncPark.print(“c\n”);
});
syncPark.setThreads(t1, t2, t3);
syncPark.start();
**原理说明**:
- 每个线程打印后唤醒下一个
- 初始时由 `main` 手动调用一次 `unpark(第一个线程)`
- 简洁、直观、不需要加锁
##### 三种方式对比总结
| 特性 | `wait/notify` | `Condition` | `LockSupport` |
| ---------- | --------------- | -------------------- | -------------- |
| 编写复杂度 | 中 | 高(结构清晰) | 最低 |
| 唤醒粒度 | 粗(notifyAll) | 精确(signal) | 精确(unpark) |
| 多线程配合 | 支持 | 支持 | 支持 |
| 初学者推荐 | ✅ | ❌(需熟练掌握 Lock) | ✅ |
### 4.17 第四章小结
synchronized互斥保护临界区的代码不会因为线程上下文切换导致交错。
wait/notify同步是让条件不满足时线程等待。
lock:可打断、锁超时、公平锁、条件变量。

#### ✅ 1. synchronized vs wait/notify vs Lock 对比表
| 特性 | `synchronized` | `wait/notify` | `ReentrantLock` + `Condition` |
| ------------------ | --------------------- | ----------------------- | ----------------------------- |
| 是否可重入 | ✅ | ✅(与synchronized配合) | ✅ |
| 是否可中断 | ❌ | ✅(wait 可中断) | ✅(lockInterruptibly) |
| 是否可限时加锁 | ❌ | ❌ | ✅(tryLock) |
| 是否支持公平锁 | ❌ | ❌ | ✅(构造函数传 true) |
| 是否支持多条件变量 | ❌(只能一个 waitSet) | ❌ | ✅(多个 Condition) |
| 使用难度 | ⭐(初学者友好) | ⭐⭐(需配合 notifyAll) | ⭐⭐⭐(灵活、控制精细) |
------
#### ✅ 2. 三种线程顺序控制方式对比
| 实现方式 | 原理 | 是否支持精确唤醒 | 实现复杂度 | 适用场景 |
| ------------- | ----------------------- | ----------------- | ---------- | ------------------ |
| `wait/notify` | 条件+锁 | ❌(需 notifyAll) | 中 | 顺序执行、互斥等待 |
| `Condition` | 多条件变量 + signal | ✅ | 高 | 多线程精准协作 |
| `LockSupport` | park/unpark“通行证机制” | ✅ | 低 | 轻量顺序控制 |
------
#### ✅ 3. 活跃性问题对比表(死锁、活锁、饥饿)
| 问题类型 | 是否运行 | 是否能得锁 | 是否释放锁 | 是否可唤醒 | 是否可检测 | 特征表现 |
| -------- | -------- | -------------- | ---------- | ---------- | ----------- | -------------------------- |
| 死锁 | ❌ 不运行 | ❌ 永远等资源 | ❌ 不释放 | ❌ | ✅ JVM可检测 | 线程互相等待,永不结束 |
| 活锁 | ✅ 运行 | ✅ 能拿锁但没用 | ✅ 不断释放 | ✅ | 🟡 较难 | 线程让来让去,无限循环 |
| 饥饿 | ❌ 不运行 | ❌ 一直抢不到锁 | ❌ 被“饿死” | ❌ | 🔴 极难 | 低优先级线程长期无调度机会 |
------
#### ✅ 4. `ReentrantLock` 公平 vs 非公平
| 类型 | 是否插队 | 性能表现 | 是否常用 | 使用方式 |
| -------- | ---------- | -------- | -------- | ------------------------- |
| 非公平锁 | ✅ 可能插队 | 高 | ✅ 默认 | `new ReentrantLock()` |
| 公平锁 | ❌ 按顺序 | 低 | ❌ 较少 | `new ReentrantLock(true)` |
# JUC上篇完结


