多线程的应用-交替打印

对于Java多线程的考察,一个经典的问题就是让两个线程交替打印输出。我们通过这个例子来回顾一下Java多线程中的相关概念。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MultiThread {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
synchronized (lock) {
System.out.println("A" + i);
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
synchronized (lock) {
System.out.println("B" + i);
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t1.start();
t2.start();
}
}

概念回顾

上面的例子非常简单,创建两个线程,用lambda表达式的方式重写了run方法。在方法中两个线程都打印0到9外加A或B的内容。

打印部分的代码块通过syncronized关键字加锁,使用的是创建出的lock对象的锁。两个线程在打印完一条之后,会调用对象的notify方法唤醒其他等待这个对象锁的线程。之后在调用wait方法释放掉这个对象的锁。这样就轮到对方了。

syncronized关键字

Java中通过syncronized关键字对代码块,对象方法,静态方法加锁。其底层原理都是获取到一个对象的锁,只有获取到锁的线程可以执行对应的代码逻辑。

对象的锁

对象的锁信息存储在对象头部。线程执行syncronized部分时会去检查对应对象的锁状态,如果是无锁的,则可以获取到,开始执行,如果是有锁的,则阻塞等待。

对象都具有notify,notifyall,wait方法。notify方法用来随机唤醒一个等待该对象锁的线程。notifyall用来唤醒所有等待该对象锁的方法。

wait方法用来真正释放该对象的锁。

在这个例子中,先调用了notify方法,唤醒其他等待的线程,准备抢锁。之后再调用wait方法,真正释放锁。释放之后其他线程才正式开抢。

线程的状态

new,runnable(running,ready),wait,block,killed等。记住一张经典的图

这个例子中,对象wait方法后当前线程进入wait状态,没有争取到锁的线程进入block状态。


多线程的应用-交替打印
http://www.bake-data.com/2024/04/27/多线程的应用-交替打印/
Author
shuchen
Posted on
April 27, 2024
Licensed under