用Java实现互斥

用Java实现互斥,java,multithreading,locking,mutex,Java,Multithreading,Locking,Mutex,我目前正在学习Java中的线程同步,并选择自己做一些测试。该程序包含几个线程,这些线程访问一个方法,将1添加到共享int,并打印哪个线程刚刚使用了该方法以及x的新值。目标是让线程从0计数到10,并按如下正确顺序打印: public int addNumbers() { x++; if (x >= 10) { running = false; } return x; } 线程: private class RunThread extends

我目前正在学习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());
        }
    }
}
为了创建互斥锁,我使用了一个可重入锁,但我有一些问题:

为什么这会保证互斥并使线程以正确的顺序打印数字…:

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();
    }
}
看起来它对我也有同样的影响。为什么我在方法中添加一个线程时它会突然起作用呢

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();
    }
}
我试着在网上阅读,但对我来说毫无意义。 请帮助我,我只是刚刚开始学习多线程

预期“正确”结果(正常计数):

一,

二,

三,

四,

五,

六,

七,

八,

九,

十,

十一,

错误结果:

二,

三,

一,

四,

五,

七,

六,

九,

八,

十,

完整代码:

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

一般来说,如果添加
sleep
“修复”类似的内容,则在未完全指定关系之前发生。定义“正确顺序”是什么。你期望发生什么?确切地说,为什么?到底发生了什么?在任何情况下,我的期望都是一个不确定的顺序。这是完全有道理的。非常感谢你!