有如下两个数组,开启两个线程,分别控制一个数组,每次输出一个字符,两个线程轮流输出。
数组一:1234567
数组二:ABCDEFG
输出结果:1A2B3C4D5E6F7G
有锁实现
wait / notify
多线程编程最基本的方法,通过 wait/notify
方法进行线程间的交互,从而实现线程间轮流输出。
public class SynchronizedTest() {
public static void main(String[] args) {
char[] ai = "1234567".toCharArray();
char[] ac = "ABCDEFG".toCharArray();
Object obj = new Object();
Thread t1 = new Thread(() -> {
synchronized (obj) {
for (char c : ai) {
System.out.print(c);
try {
obj.notify(); // 唤醒其它线程
obj.wait(); // 阻塞 t1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
obj.notify();
}
});
Thread t2 = new Thread(() -> {
synchronized (obj) {
for (char c : ac) {
System.out.print(c);
try {
obj.notify(); // 唤醒其它线程
obj.wait(); // 阻塞 t2
} catch (InterruptedException e) {
e.printStackTrace();
}
}
obj.notify();
}
});
t1.start();
t2.start();
}
}
LockSupport
LockSupport
是一个线程阻塞工具类,可以让线程在任意位置阻塞或者唤醒。
方法介绍:
- LockSupport.park(),阻塞当前线程
- LockSupport.park(线程名),阻塞指定线程
- LockSupport.unpark(线程名),唤醒指定线程
public class LockSupportTest {
private static Thread t1, t2;
public static void main(String[] args) {
char[] ai = "1234567".toCharArray();
char[] ac = "ABCDEFG".toCharArray();
t1 = new Thread(() -> {
for (char c : ai) {
System.out.print(c);
LockSupport.unpark(t2); // 唤醒 t2
LockSupport.park(); // 阻塞 t1
}
});
t2 = new Thread(() -> {
for (char c : ac) {
LockSupport.park(); // 阻塞 t2
System.out.print(c);
LockSupport.unpark(t1); // 唤醒 t1
}
});
t1.start();
t2.start();
}
}
无锁实现
volatile
利用 volatile
线程可见性的特性,当 displayFlag
为 true
时,第一个线程输出,为 false
时,第二个线程输出,如此反复。
public class VolatileTest {
private static volatile boolean displayFlag = true;
public static void main(String[] args) {
char[] ai = "1234567".toCharArray();
char[] ac = "ABCDEFG".toCharArray();
Thread t1 = new Thread(() -> {
for (char c : ai) {
while (!displayFlag) {
}
System.out.print(c);
displayFlag = false;
}
});
Thread t2 = new Thread(() -> {
for (char c : ac) {
while (displayFlag) {
}
System.out.print(c);
displayFlag = true;
}
});
t1.start();
t2.start();
}
}
Atomic 原子类
利用原子类中的方法具备原子性的特性
public class AtomicTest {
private static AtomicInteger atomicFlag = new AtomicInteger(0);
public static void main(String[] args) {
char[] ai = "1234567".toCharArray();
char[] ac = "ABCDEFG".toCharArray();
Thread t1 = new Thread(() -> {
for (char c : ai) {
while (atomicFlag.get() == 1) {
}
System.out.print(c);
atomicFlag.set(1);
}
});
Thread t2 = new Thread(() -> {
for (char c : ac) {
while (atomicFlag.get() == 0) {
}
System.out.print(c);
atomicFlag.set(0);
}
});
t1.start();
t2.start();
}
}