从别处看来得题目,觉得蛮有意思,记录一下;
已知数组 A 内容为1、2、3、4...52,数组 B 内容为 26 个英文字母,使用两个线程分别输入两个数组,然后使程序运行打印内容为 12a34b56c78e... 的规律,请给出代码实现?
这个问题的核心就是两个线程交替等待执行,对应到java中就是线程之间的协同;首先用第一种实现,自旋锁的方式:
首先看一种错误的方式:
先是打印数值类型的类:
public class PrintNumber implements Runnable {
private int number[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52};
private Boolean isNumber;
public PrintNumber(Boolean isNumber) {
this.isNumber = isNumber;
}
@Override
public void run() {
int j = 0;
for (int i = 0; i < number.length; i++) {
while (!isNumber) {
Thread.yield();
}
j++;
System.out.print(number[i]);
if (j == 2) {
isNumber = false;
j = 0;
}
}
isNumber = false;
}
}
然后是打印字符类型的类
public class PrintChar implements Runnable {
private char charArray[] = {'a', 'b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q','r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
private boolean isNumber;
public PrintChar(boolean isNumber) {
this.isNumber = isNumber;
}
@Override
public void run() {
for (int i = 0; i < charArray.length; i++) {
while (isNumber) {
Thread.yield();
}
System.out.print(charArray[i]);
isNumber = true;
}
isNumber = true;
}
public static void main(String[] args) {
Boolean isNumber = true;
Thread thread1 = new Thread(new PrintNumber(isNumber));
Thread thread2 = new Thread(new PrintChar(isNumber));
thread1.start();
thread2.start();
}
}
执行结果发现,只输入了1 2;原因在于定义的变量isNumber是每个线程中的变量值是不一样的,没有内存的可见性,所以数值类型执行了2次之后不执行了,字符类型的从一开始就不会执行,每个线程是自己的变量值;所以要修改成AtomicBoolean;修改后的代码如下所示
public class PrintNumber implements Runnable {
private int number[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52};
private AtomicBoolean isNumber;
public PrintNumber(AtomicBoolean isNumber) {
this.isNumber = isNumber;
}
@Override
public void run() {
int j = 0;
for (int i = 0; i < number.length; i++) {
while (!isNumber.get()) {
Thread.yield();
}
j++;
System.out.print(number[i]);
if (j == 2) {
isNumber.set(false);
j = 0;
}
}
isNumber.set(false);
}
}
public class PrintChar implements Runnable {
private char charArray[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
private AtomicBoolean isNumber;
public PrintChar(AtomicBoolean isNumber) {
this.isNumber = isNumber;
}
@Override
public void run() {
for (int i = 0; i < charArray.length; i++) {
while (isNumber.get()) {
Thread.yield();
}
System.out.print(charArray[i]);
isNumber.set(true);
}
isNumber.set(true);
}
public static void main(String[] args) {
AtomicBoolean isNumber = new AtomicBoolean(true);
Thread thread1 = new Thread(new PrintNumber(isNumber));
Thread thread2 = new Thread(new PrintChar(isNumber));
thread1.start();
thread2.start();
}
}
基本思路就是,循环打印出数值和字符,然后在分别循环2次和一次之后,设置是否是数值类型的boolean,每次在打印之前判断是否满足条件,不满足就一直循环等待;
2.采用LockSupport的方式
LockSupport使用park和unpark来实现线程的阻塞和唤醒,只有一个许可可以使用,如果这个许可没有被占用,那么当前线程继续执行,如果许可被占用,线程处于阻塞状态,直到获取到许可;代码如下所示
public class LockSupportPrintNumber extends Thread {
private int number[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52};
private Thread thread;
public void setThread(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
int count = 0;
for (int i = 0; i < number.length; i++) {
if (count == 2) {
count = 0;
LockSupport.unpark(thread);
LockSupport.park();
}
System.out.print(number[i]);
count++;
}
LockSupport.unpark(thread);
}
}
public class LockSupportPrintChar extends Thread {
private char charArray[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
private Thread thread;
public void setThread(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
int count = 0;
LockSupport.park();
for (int i = 0; i < charArray.length; i++) {
System.out.print(charArray[i]);
count++;
if (count == 1) {
count = 0;
LockSupport.unpark(thread);
LockSupport.park();
}
}
LockSupport.unpark(thread);
}
}
public static void main(String[] args) {
LockSupportPrintChar thread2 = new LockSupportPrintChar();
LockSupportPrintNumber thread1 = new LockSupportPrintNumber();
thread1.setThread(thread2);
thread2.setThread(thread1);
thread1.start();
thread2.start();
}
参考文章: