多线程.循环按顺序定义数字

153 阅读1分钟

命题:实现三个线程按顺序打印数字的功能。具体来说,线程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();
        }
    }
}