面试题如下:
本题考查的是线程通信的问题。更侧重的是考查sync+wait+notify的组合使用。
比较优的解法。
import java.util.concurrent.locks.LockSupport;
public class Maureen_LockSupport {
static Thread t1 = null, t2 = null;
public static void main(String[] args) throws Exception {
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();
System.out.print(c);
LockSupport.unpark(t1);
}
}, "t2");
t1.start();
t2.start();
}
}
运行结果:1A2B3C4D5E6F7G
public class Maureen_CAS {
enum ReadyToRun {
T1, T2
}
static volatile ReadyToRun r = ReadyToRun.T1;
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
for (char c : aI) {
while (r != ReadyToRun.T1) {
//空转,一直占着CPU,也就是自旋(原地打转)
}
System.out.print(c);
r = ReadyToRun.T2; //每输出一个字符,就将r标记进行修改
}
}, "t1").start();
new Thread(() -> {
for (char c : aC) {
while (r != ReadyToRun.T2) {
}
System.out.print(c);
r = ReadyToRun.T1;
}
}, "t2").start();
}
}
输出结果:1A2B3C4D5E6F7G
import java.util.concurrent.atomic.AtomicInteger;
public class Maureen_AtomicInteger {
static AtomicInteger threadNo = new AtomicInteger(1);
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".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();
}
}
输出结果:1A2B3C4D5E6F7G
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Maureen_BlockingQueue {
static BlockingQueue q1 = new ArrayBlockingQueue(1);
static BlockingQueue q2 = new ArrayBlockingQueue(1);
public static void main(String[] args) throws Exception {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
for (char c : aI) {
System.out.print(c);
try {
q1.put("ok");
q2.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1").start();
new Thread(() -> {
for (char c : aC) {
try {
q1.take(); //等着q1中有内容,取出内容再继续运行;如果没有内容,就阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(c);
try {
q2.put("ok");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t2").start();
}
}
输出结果:1A2B3C4D5E6F7G
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class Maureen_PipedStream {
public static void main(String[] args) throws IOException {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
PipedInputStream input1 = new PipedInputStream();
PipedInputStream input2 = new PipedInputStream();
PipedOutputStream output1 = new PipedOutputStream();
PipedOutputStream output2 = new PipedOutputStream();
input1.connect(output2);
input2.connect(output1);
String msg = "Your Turn";
new Thread(() -> {
byte[] buffer = new byte[9];
try {
for (char c : aI) {
input1.read(buffer);
if (new String(buffer).equals(msg)) {
System.out.print(c);
}
output1.write(msg.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}, "t1").start();
new Thread(() -> {
byte[] buffer = new byte[9];
try {
for (char c : aC) {
System.out.print(c);
output2.write(msg.getBytes());
input2.read(buffer);
if (new String(buffer).equals(msg)) {
continue;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}, "t2").start();
}
}
输出结果:A1B2C3D4E5F6G7。该方法效率很低。
//要使用wait和notify,要对一个对象加锁,才能在其中进行notify和wait的操作
public class Maureen_sync_wait_notify_00 {
public static void main(String[] args) {
final Object o = new Object();
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
synchronized (o) {// 不能使用this,因为代码块中是一个匿名内部类,如果用this,那么和下面代码块的this不是同一个对象,不能构成同步
for (char c : aI) {
System.out.print(c);
try {
o.notify(); // 叫醒等待队列里的任意一个,notifyAll是叫醒所有线程
o.wait(); // 让出锁 运行中的线程进入等待队列中,与此同时将锁释放
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify(); // 必须,否则无法停止程序。因为无论哪个线程先运行完,总有个线程处于wait状态,只有叫醒该线程程序才会运行完
}
}, "t1").start();
new Thread(() -> {
synchronized (o) {// 拿不到锁的时候就在等待队列中
for (char c : aC) {
System.out.print(c);
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
}, "t2").start();
}
}
输出结果:1A2B3C4D5E6F7G
执行流程如下:
持有锁之后就执行输出。
//sync_wait_notify程序无法限制哪个线程先运行,因此在这个程序里限制哪个线程先运行
public class Maureen_sync_wait_notify_01 {
private static volatile boolean t2Started = false;
public static void main(String[] args) {
final Object o = new Object();
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
synchronized (o) {
while (!t2Started) { //限制t2先运行,如果t2没有先运行,t1就先等待
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (char c : aI) {
System.out.print(c);
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
},"t1").start();
new Thread(()->{
synchronized(o) {
for(char c: aC) {
System.out.print(c);
t2Started = true;
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
},"t2").start();
}
}
输出结果:A1B2C3D4E5F6G7
import java.util.concurrent.CountDownLatch;
//使用CountDownLatch限制线程运行顺序,以下是限制线程2先运行
public class Maureen_sync_wait_notify_02 {
private static CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) {
final Object o = new Object();
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o) {
for (char c : aI) {
System.out.print(c);
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
}, "t1").start();
new Thread(() -> {
synchronized (o) {
for (char c : aC) {
System.out.print(c);
latch.countDown();
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
}, "t2").start();
}
}
/**
* 线程调用start()函数,并不意味着线程立即占用CPU运行,而是进入CPU的等待队列中,即进入Ready状态。根据操作系统的调度,决定选择哪个线程运行
*/
输出结果:A1B2C3D4E5F6G7
线程状态迁移图: