前言:這道題主要考察的就是,多線程之間的通信、喚醒、切換問題。
B站上看到馬士兵老師的視頻:這道大廠面試題區分平庸與卓越
部分解法整理如下:
LockSupport實現方式
/**
* @ClassName: LockSupport
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* LockSupport實現
* @author: XZQ
* @create: 2020/3/15 15:24
**/
public class LockSupportDemo {
static Thread t1 = null, t2 = null;
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阻塞 當前線程阻塞
}
}, "t1");
t2 = new Thread(() -> {
for (char c : aC) {
LockSupport.park();//t2阻塞
System.out.print(c);
LockSupport.unpark(t1);//叫醒t1
}
}, "t2");
t1.start();
t2.start();
}
}
CAS實現方式
/**
* @ClassName: CASDemo
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* CAS實現
* @author: XZQ
* @create: 2020/3/15 15:56
**/
public class CASDemo {
enum ReadToRun {T1, T2}//枚舉 規範參數的形式
static volatile ReadToRun r = ReadToRun.T1;//保證可見性
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
for (char c : aI) {
while (r != ReadToRun.T1) {
}
System.out.print(c);
r = ReadToRun.T2;
}
}, "t1").start();
new Thread(() -> {
for (char c : aC) {
while (r != ReadToRun.T2) {
}
System.out.print(c);
r = ReadToRun.T1;
}
}, "t2").start();
}
}
ReentrantLock_Condition實現方式
/**
* @ClassName: ReentrantLockDemo
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* ReentrantLock&Condition 實現方式
* 優點:支持指定線程喚醒和指定線程等待
* @author: XZQ
* @create: 2020/3/15 16:27
**/
public class ReentrantLock_ConditionDemo {
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
Lock lock = new ReentrantLock();//默認非公平鎖
Condition condition1 = lock.newCondition();//隊列
Condition condition2 = lock.newCondition();
new Thread(() -> {
try {
lock.lock();
for (char c : aI) {
System.out.print(c);
condition2.signal();
condition1.await();
}
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 e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t2").start();
}
}
ReentrantLock實現方式
/**
* @ClassName: ReentrantLockDemo
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* ReentrantLock 實現方式
* @author: XZQ
* @create: 2020/3/15 16:27
**/
public class ReentrantLockDemo {
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
ReentrantLock reentrantLock = new ReentrantLock();//默認非公平鎖
Condition condition = reentrantLock.newCondition();
new Thread(() -> {
try {
reentrantLock.lock();
for (char c : aI) {
System.out.print(c);
condition.signal();
condition.await();
}
condition.signal();//必須 否則無法停止程序
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}, "t1").start();
new Thread(() -> {
try {
reentrantLock.lock();
for (char c : aC) {
System.out.print(c);
condition.signal();
condition.await();
}
condition.signal();//必須 否則無法停止程序
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}, "t2").start();
}
}
Synchronized實現方式
/**
* @ClassName: SynchronizedDemo
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* Synchronized實現
* @author: XZQ
* @create: 2020/3/15 16:15
**/
public class SynchronizedDemo {
static Object object = new Object();
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
synchronized (object) {
for (char c : aI) {
System.out.print(c);
try {
object.notify();//先notify再wait
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
object.notify();//必須 否則無法停止程序
}
}, "t1").start();
new Thread(() -> {
synchronized (object) {
for (char c : aC) {
System.out.print(c);
try {
object.notify();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
object.notify();//必須 否則無法停止程序
}
}, "t2").start();
}
}
TransferQueue 實現方式
/**
* @ClassName: TransferQueueDemo
* @description: 兩個線程交叉打印,一個打印數字,一個打印小寫字母,結果爲 1A2B3C4D5E6F
* TransferQueue 實現方式
* @author: XZQ
* @create: 2020/3/15 16:54
**/
public class TransferQueueDemo {
public static void main(String[] args) {
TransferQueue<Character> queue = new LinkedTransferQueue<>();
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
try {
for (char c : aC) {
System.out.print(queue.take());
queue.transfer(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}, "t1").start();
new Thread(() -> {
try {
for (char c : aI) {
queue.transfer(c);
System.out.print(queue.take());
}
} catch (Exception e) {
e.printStackTrace();
}
}, "t2").start();
}
}
除此之外還有阻塞隊列等等一系列解法。