前言:这道题主要考察的就是,多线程之间的通信、唤醒、切换问题。
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();
}
}
除此之外还有阻塞队列等等一系列解法。