题目:线程 A 生成随机数,另外两个线程来猜数,线程 A 可以告诉猜的结果是大还是小,两个线程都猜对后,游戏结束,编写代码完成。
一、Semaphore
多个线程可以同时操作同一信号量,由此实现线程同步。
public class Main {
private static Semaphore s1 = new Semaphore(0);
private static Semaphore s2 = new Semaphore(0);
// 待判断的线程
private static Queue<Semaphore> judgeQueue = new LinkedList<>();
// 保存线程猜的数
private static Map<Semaphore, Integer> guessMap = new ConcurrentHashMap<>();
// 保存判断结果
private static Map<Semaphore, Integer> resMap = new ConcurrentHashMap<>();
// 保存猜数线程二分过程中的左右边界
private static Map<Semaphore, Pair<Integer, Integer>> edgeMap = new ConcurrentHashMap<>();
private static Set<Semaphore> set = new HashSet<>();
public static void main(String[] args) {
new Thread(Main::judge, "判断线程").start();
new Thread(() -> guess(s1), "猜线程1").start();
new Thread(() -> guess(s2), "猜线程2").start();
}
private static void judge() {
System.out.println("开始猜数!");
int num = ThreadLocalRandom.current().nextInt(100);
System.out.printf("要猜的数是 %d\n", num);
set.add(s1);
set.add(s2);
s1.release();
s2.release();
while (true) {
while (!judgeQueue.isEmpty()) {
Semaphore s = judgeQueue.poll();
Integer guessNum = guessMap.get(s);
if (guessNum != null) {
if (guessNum > num) {
resMap.put(s, 1);
} else if (guessNum < num) {
resMap.put(s, 2);
} else {
resMap.put(s, 0);
}
s.release();
} else {
}
}
if (set.isEmpty()) {
System.out.println("所有线程猜数完成!\n");
break;
}
}
}
private static void guess(Semaphore s) {
Pair<Integer, Integer> edge = new Pair<>(0, 100);
edgeMap.put(s, edge);
int guess = 0;
while (true) {
try {
s.acquire();
guess = guessNum(guess, s);
if (guess != -1) {
guessMap.put(s, guess);
judgeQueue.add(s);
} else {
System.out.printf("%s 猜数成功!\n", Thread.currentThread().getName());
set.remove(s);
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static int guessNum(int guess, Semaphore s) {
Pair<Integer, Integer> pair = edgeMap.get(s);
if (resMap.containsKey(s)) {
int res = resMap.get(s);
// 1 表示猜大了
if (res == 1) {
edgeMap.put(s, new Pair<>(pair.getKey(), guess - 1));
} else if (res == 2) {
edgeMap.put(s, new Pair<>(guess + 1, pair.getValue()));
} else {
// 猜中了
return -1;
}
guess = (pair.getKey() + pair.getValue()) / 2;
} else {
guess = ThreadLocalRandom.current().nextInt(100);
}
System.out.printf("%s 猜的数是:%s\n", Thread.currentThread().getName(), guess);
return guess;
}
}
暂时没想到更好的解法,也欢迎大家指教。