Java 中的互斥实现

Mutex implementation in Java

我目前正在 Java 学习线程同步,并选择自己做一些测试。该程序包含几个线程,这些线程访问一个方法以将 1 加到共享 int 并打印哪个线程刚刚使用了该方法以及 x 的新值是什么。目标是让线程数从 0 增加到 10,并以正确的顺序打印它,如下所示:

public int addNumbers() {
    x++;
    if (x >= 10) {
        running = false;
    }
    return x;
}

主题:

private class RunThread extends Thread {
    public void run() {
        while (running) {
            System.out.println(addNumbers());
        }
    }
}

为了创建 Mutex,我使用了 ReentrantLock,但我有一些问题:

为什么这保证了 Mutex 并使线程以正确的顺序打印数字...:[=​​17=]

lock.lock();
System.out.println(addNumbers());
lock.unlock();

...虽然这不是?:

public int addNumbers() {
    lock.lock();
    try {
        x++;
        if (x >= 10) {
            running = false;
        }
        return x;
    } finally {
        lock.unlock();
    }
}

看起来它对我做了同样的事情。为什么我在方法里加了一个Thread.sleep就突然生效了?:

public int addNumbers() {
    lock.lock();
    try {
        x++;
        if (x >= 10) {
            running = false;
        }
        return x;
    } finally {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.unlock();
    }
}

我试图在线阅读它,但它对我来说没有任何意义。 请帮助和善待,我才刚刚开始学习多线程。

预期 "right" 结果(正常计数):

1

2

3

4

5

6

7

8

9

10

11

错误结果:

2

3

1

4

5

7

6

9

8

10

完整代码:

public class LockTest {
    int x = 0;
    boolean running = true;
    private final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        LockTest t1 = new LockTest();
    }

    public LockTest() {
        init();
    }

    public int addNumbers() {
        x++;
        if (x >= 10) {
            running = false;
        }
        return x;
    }

    private void init() {
        Thread t1 = new RunThread();
        Thread t2 = new RunThread();
        Thread t3 = new RunThread();
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }

    private class RunThread extends Thread {
        public void run() {
            while (running) {
                lock.lock();
                System.out.println(this.getName() + ": " + addNumbers());
                lock.unlock();
            }
        }
    }
}

在一种情况下,您有

lock.lock();
System.out.println(this.getName() + ": " + addNumbers());
lock.unlock();

因此,所有线程都想同时执行这些行,但一次只能执行一个。所以第一个线程获得锁,从而防止其他线程获得它,然后递增并打印值,然后释放锁。然后另一个线程可以获得锁,递增和打印,然后释放锁。因此,您将获得按升序打印的值。

在第二种情况下你只有

 System.out.println(this.getName() + ": " + addNumbers());

因此,所有线程都可以并发执行。但是,在 addNumbers 中,线程必须获取锁才能增加数字。因此数字以正确的顺序递增,但由于打印不在互斥量内,因此无法保证顺序。示例:

 - Thread 1: acquire the lock
 - Thread 1: increment x (x = 1)
 - Thread 1: read the value returned by addNumbers (= 1) to print it
 - Thread 1: release the lock
 - Thread 2: acquire the lock
 - Thread 2: increment x (x = 2)
 - Thread 2: read the value returned by addNumbers (= 2) to print it
 - Thread 2: release the lock
 - Thread 2: print the read value: 2
 - Thread 1: print the read value: 1