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
我目前正在 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