Java ReentrantLock的使用demo:线程交替打印ABCABC...序列

笔/面试的时候常常遇到的一个问题,就是多个线程进行交替的打印任务:

import java.util.concurrent.locks.ReentrantLock;

public class PrintTask extends Thread {
    private String task;
    private Integer id;
    private static Integer taskId;
    private static Integer taskCount;
    private ReentrantLock lock;

    public PrintTask(String task, Integer id, Integer taskId, Integer taskCount, ReentrantLock lock) {
        this.task = task;
        this.setName("PrintTask-" + task);
        this.id = id;
        PrintTask.taskId = taskId;
        PrintTask.taskCount = taskCount;
        this.lock = lock;
    }

    @Override
    public void run() {
        while (true) {
            lock.lock();
            if (taskId % PrintTask.taskCount == id) {
                System.out.println(task);
                taskId = taskId == PrintTask.taskCount - 1 ? 0 : taskId + 1;
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        String[] tasks = new String[]{"A", "B", "C"};
        //使用公平锁,当前线程打印完之后下一次不会马上又轮到自己去获取锁
        ReentrantLock lock = new ReentrantLock(true);
        PrintTask[] printTasks = new PrintTask[tasks.length];
        for (int i = 0; i < tasks.length; i++) {
            printTasks[i] = new PrintTask(tasks[i], i, 0, tasks.length, lock);
        }
        for (PrintTask printTask : printTasks) {
            printTask.start();
        }
    }
}

看一下运行结果:

res.png

没毛病,顺利输出了,然后再看看VisualVM:
VM01.png

虽然输出结果没问题,但是线程并没有严格的交替执行,是因为比如 Aunlock(),下次具体会是另外的那一个线程 ( B or C ) 获得锁还不一定。如果是 B 拿到了,就会如期的打印,但是如果是 C 拿到,又不打印,然后就会继续让出,而有可能又给了 AA 又会继续让出,直到 B 拿到并顺利打印。

也就是说因该给每一个线程加一个条件标记,让每次当前的线程打印完毕之后,能够准确的指定让给下一个应该打印的线程。

可以使用附随LockCondition来解决这个问题:

你可能感兴趣的:(Java ReentrantLock的使用demo:线程交替打印ABCABC...序列)