我在看官方Java Tutorial由 Oracle 提供,我想将我的知识付诸实践。
我想看Thread Interference在行动中并使用 Intrinsic Locks and Synchronization 解决它.所以我创建了一个名为 Counter 的类:
- 两个都初始化为 0 的字段。
- 递增和递减它们的值的方法。
- 打印值的方法。
.
public class Apple {
public static void main(String[] args) {
Counter myCounter = new Counter();
Thread a = new Thread(myCounter);
Thread b = new Thread(myCounter);
a.start();
b.start();
}
}
class Counter implements Runnable {
public int a = 0;
public int b = 0;
void incA() {
++a;
}
void decA() {
--a;
}
void incB() {
++b;
}
void decB() {
--b;
}
void printValues() {
System.out.println("a: " + a + " | b: " + b);
}
public void run() {
for (int i = 0; i < 10; i++) {
incA();
decA();
incB();
decB();
printValues();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
首先,我在不使用内在锁或同步的情况下运行我的程序,输出是我所期望的,线程干扰。
...
a: 0 | b: 0
a: 0 | b: 1
a: 0 | b: 0
a: 1 | b: 0
a: 0 | b: 0
...
现在我想使用内部锁来解决这个问题,这样当一个线程递增或递减 a 时,另一个线程可以同时更改 b,而不是使用会阻止这种情况的同步方法。
所以我添加了两个新字段(锁)和使用内部锁的同步块(synchronized block)。这是新代码:
class Counter implements Runnable {
public int a = 0;
public int b = 0;
Object lock1 = new Object();
Object lock2 = new Object();
void incA() {
synchronized (lock1) {
++a;
}
}
void decA() {
synchronized (lock1) {
--a;
}
}
void incB() {
synchronized (lock2) {
++b;
}
}
void decB() {
synchronized (lock2) {
--b;
}
}
void printValues() {
System.out.println("a: " + a + " | b: " + b);
}
public void run() {
for (int i = 0; i < 10; i++) {
incA();
decA();
incB();
decB();
printValues();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我没有对 main 方法做任何更改,所以我没有包含它。但是我将这段代码运行了三次,这是最后一次尝试的输出:
...
a: 0 | b: 0
a: 0 | b: 0
a: 0 | b: 1
a: 0 | b: 0
我做错了什么?代码应该是什么样子?
我只想要一个使用内部锁的简单示例代码。
最佳答案
printValues()
读取并打印值,同时另一个线程递增或递减它们:它不是同步的。即使是,它也可以在调用另一个线程的 incB()
和 decB()
之间读取和打印 b
。
所以你可以拥有
- 线程 1 递增 b --> b = 1
- 线程 2 读取并打印 b --> b 打印为 1
- 线程 1 递减 b --> b = 0
如果没有人认为 b 不同于 0,那么 incB();decB()
应该是单个原子操作,将这两个调用放在一个同步块(synchronized block)中,并且b 的读取也应该放入同步块(synchronized block)中,使用相同的锁:
class Counter implements Runnable {
private int a = 0;
private int b = 0;
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private void incA() {
++a;
}
private void decA() {
--a;
}
private void incB() {
++b;
}
private void decB() {
--b;
}
private void printValues() {
System.out.println("a: " + a + " | b: " + b);
}
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (lock1) {
incA();
decA();
}
synchronized (lock2) {
incB();
decB();
}
synchronized (lock1) {
synchronized (lock2) {
printValues();
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
关于java - 如何在java中使用内部锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34691903/