多线程通信问题是一个老生常谈的知识点,今天有空通过一个编程题把所有的实现方式整理一遍。
实现方式有:
1、通过全局变量实现(有多种实现方式)
2、通过wait,notify,notifyAll实现
3、通过lock,condition实现
4、通过LockSupport实现
已知两个字符串"123456789"和"ABCDEFGGH",请用两个线程交替打出字符串每个字符,要求数字首先出现。
这是一道典型的多线程通信的编程题,下面给出多种方式的实现。
/***
* 使用枚举全局变量实现,实现方式类似与自旋锁原理
* 不满足条件的时候就一直空转。
* 通过r公共变量控制两个线程交替执行
*/
public class T01_CAS {
// 定义两个枚举
enum ReadyToRun{
T1,T2};
// 定义r变量,控制线程执行
static volatile ReadyToRun r = ReadyToRun.T1;
public static void main(String[] args) {
char[] aI = "123456789".toCharArray();
char[] aC = "ABCDEFGGH".toCharArray();
new Thread(() ->{
for (char c : aI) {
// r变量不是T1就空转,直到T1才执行
while (r != ReadyToRun.T1){
}
System.out.print(c);
r = ReadyToRun.T2;
}
},"t1").start();
new Thread(()->{
for (char c : aC) {
while (r != ReadyToRun.T2){
}
System.out.print(c);
r = ReadyToRun.T1;
}
},"t2").start();
}
}
执行结果:
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0
也可以通过AtomicInteger等原子类来实现:
public class T01_AtomicInteger {
// 控制两个线程执行顺序
static AtomicInteger threadNo = new AtomicInteger(1);
public static void main(String[] args) {
char[] aI = "123456789".toCharArray();
char[] aC = "ABCDEFGGH".toCharArray();
new Thread(() ->{
for (char c : aI) {
while (threadNo.get() != 1){
}
System.out.print(c);
threadNo.set(2);
}
},"t1").start();
new Thread(()->{
for (char c : aC) {
while (threadNo.get() != 2){
}
System.out.print(c);
threadNo.set(1);
}
},"t2").start();
}
}
执行结果:
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0
public class T01_Sync_wait_notify {
// 全局变量,控制让T1先执行,先出数字
static boolean t1IsStart = false;
public static void main(String[] args) {
final Object lockObject = new Object(); // 锁对象
char[] aI = "123456789".toCharArray();
char[] aC = "ABCDEFGGH".toCharArray();
new Thread(() ->{
synchronized (lockObject) {
for (char c : aI) {
if(!t1IsStart){
//T1执行时发现标记为未启动,修改标记位
t1IsStart = true;
}
System.out.print(c);
try {
lockObject.notify();
lockObject.wait(); // 让出锁
}catch (Exception e){
e.printStackTrace();
}
}
lockObject.notify();
}
},"t1").start();
new Thread(()->{
synchronized (lockObject) {
for (char c : aC) {
if(!t1IsStart){
// 若T2先抢到锁,发现T1未执行,则主动让出锁让T1先执行
try {
lockObject.wait(); // 让出锁
}catch (Exception ex){
ex.printStackTrace();
}
}
System.out.print(c);
try {
lockObject.notify();
lockObject.wait(); // 让出锁
}catch (Exception ex){
ex.printStackTrace();
}
}
lockObject.notify();
}
},"t2").start();
}
}
执行结果:
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0
public class T01_Lock_Condition {
public static void main(String[] args) {
char[] aI = "123456789".toCharArray();
char[] aC = "ABCDEFGGH".toCharArray();
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition(); // 控制线程1
Condition condition2 = lock.newCondition(); // 控制线程2
new Thread(() ->{
try{
lock.lock();
for (char c : aI) {
System.out.print(c);
condition2.signal();// 唤醒线程2
condition1.await();// 线程1等待
}
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t1").start();
new Thread(()->{
try{
lock.lock();
for (char c : aC) {
System.out.print(c);
condition1.signal();
condition2.await();
}
condition1.signal();
}catch (Exception ex){
ex.printStackTrace();
}finally {
lock.unlock();
}
},"t2").start();
}
}
执行结果:
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0
public class T01_LockSupport {
static Thread t1 = null, t2 = null;
public static void main(String[] args) {
char[] aI = "123456789".toCharArray();
char[] aC = "ABCDEFGGH".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线程获得执行许可
}
},"t2");
t1.start();
t2.start();
}
}
执行结果:
```java
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0
下面实现方式:
3、通过lock,condition实现
4、通过LockSupport实现
是比较优雅的实现方式.