命题:实现三个线程按顺序打印数字的功能。具体来说,线程1、线程2和线程3会按照顺序打印数字,每个线程每次打印5个数字,直到打印的数字达到75。
public static void main(String[] args) {
PrintNumbersInOrder printNumbersInOrder = new PrintNumbersInOrder();
new Thread(() -> printNumbersInOrder.printNumber(1)).start();
new Thread(() -> printNumbersInOrder.printNumber(2)).start();
new Thread(() -> printNumbersInOrder.printNumber(3)).start();
}
public class PrintNumbersInOrder {
//初始
private final Semaphore semaphore1 = new Semaphore(1);
private final Semaphore semaphore2 = new Semaphore(0);
private final Semaphore semaphore3 = new Semaphore(0);
private int count = 1;
public void printNumber(int threadNum) {
boolean stop = false; //标记循环状态,只有打印出错才给值
while (!stop) {
try {
if (threadNum == 1) {
semaphore1.acquire();
} else if (threadNum == 2) {
semaphore2.acquire();
} else {
semaphore3.acquire();
}
for (int i = 0; i < 5; i++) {
if (count > 75) break;
System.out.println("线程 " + threadNum + ":" + count++);
}
} catch (InterruptedException e) {
e.printStackTrace();
stop = true;
} finally {
// 释放信号量让下一个线程开始打印
if (threadNum == 1) {
semaphore2.release();
} else if (threadNum == 2) {
semaphore3.release();
} else {
semaphore1.release();
}
}
}
}
}
知识点:(1)信号量的初始值表示了可以立即获得许可的线程数量。如果信号量的值为0,那么线程将会阻塞,直到其他线程释放一个许可。如果信号量的值大于0,那么线程可以立即获得一个许可,并继续执行。
如果有很多线程,靠朴素的信号量就不太合适了。 可以用一个ReentrantLock和一个Condition[]数组实现。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PrintNumbersInOrder {
private final ReentrantLock lock = new ReentrantLock();
private final Condition[] conditions;
private int count = 1;
private int currentThreadNum = 0;
private static final int THREAD_COUNT = 10;
public PrintNumbersInOrder() {
conditions = new Condition[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
conditions[i] = lock.newCondition();
}
}
public void printNumber(int threadNum) {
while (true) {
lock.lock();
try {
while (threadNum != currentThreadNum) {
conditions[threadNum].await();
}
for (int i = 0; i < 5; i++) {
if (count > 75) break;
System.out.println("线程 " + threadNum + ":" + count++);
}
currentThreadNum = (currentThreadNum + 1) % THREAD_COUNT;
conditions[currentThreadNum].signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
PrintNumbersInOrder printNumbersInOrder = new PrintNumbersInOrder();
for (int i = 0; i < THREAD_COUNT; i++) {
final int threadNum = i;
new Thread(() -> printNumbersInOrder.printNumber(threadNum)).start();
}
}
}