不同对象上的同步语句可以交错吗?
Can synchronized statements on different objects interleave?
我正在研究关键字synchronized
,我不明白是否可以在同一个class中有2个同步语句交错;示例:
我用这些简单的方法和两个锁对象做了一个 class:
public class Locker1 {
private Object lock1= new Object();
private Object lock2= new Object();
public void printL1() {
synchronized(lock1) {
for(int i=0; i<50;i++) {
System.out.println(i);
}
}
}
public void printL2() {
synchronized(lock2) {
for(int i=0; i<50;i++) {
System.out.println("-"+i);
}
}
}
}
我创建了两个不同的线程,它们只调用 printL1
和 printL2
,在我的理解中,我认为因为这是两个不同的锁,所以我会看到交替打印正数和负数,因为并发是可能的,但我尝试了很多次 printL2
总是完全发生在 printL1
之后,不是一次我看到正数之间的负数,我是不是在同步时遗漏了什么?
这是剩余的代码
public class ThreadA extends Thread {
private Locker1 l1;
public ThreadA(Locker1 l1) {
this.l1=l1;
}
public void run() {
l1.printL1();
}
}
public class ThreadB extends Thread {
private Locker1 l1;
public ThreadB(Locker1 l1) {
this.l1=l1;
}
public void run() {
l1.printL2();
}
}
和主要 class:
public class Main {
public static void main(String[] args) {
Locker1 l1=new Locker1();
ThreadA tA=new ThreadA(l1);
ThreadB tB=new ThreadB(l1);
tA.start();
tB.start();
}
}
交织如预期发生;仅进行 50 次迭代就很难看到,因此进行更多次迭代可以显示出来
你对线程和锁的理解是正确的。由于 Locker1.printL1()
和 Locker1.printL2()
将锁授予不同的对象,一个线程访问 Locker1.printL1()
而另一个线程访问 Locker1.printL2()
不应相互阻塞。
您在 printL1 之后看到完整的 printL2 结果的原因是 CPU 的工作太少了。 50 次迭代只需几分之一毫秒即可完成。在需要 context switch 之前,任务已完成。
让任务休眠一小段时间,您可以看到线程的产出情况。
public class Locker1 {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void printL1() {
synchronized (lock1) {
for (int i = 0; i < 50; i++) {
System.out.println(i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void printL2() {
synchronized (lock2) {
for (int i = 0; i < 50; i++) {
System.out.println("-" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
输出:
0
-0
1
-1
2
-2
3
-3
4
-4
5
-5
6
-6
7
-7
8
-8
9
-9
10
-10
11
-11
12
-12
13
-13
14
-14
15
-15
16
-16
17
-17
18
-18
19
-19
20
-20
21
-21
22
-22
-23
23
24
-24
25
-25
26
-26
27
-27
28
-28
29
-29
30
-30
31
-31
32
-32
33
-33
34
-34
35
-35
36
-36
37
-37
38
-38
39
-39
40
-40
41
-41
42
-42
43
-43
44
-44
45
-45
46
-46
47
-47
48
-48
49
-49
我正在研究关键字synchronized
,我不明白是否可以在同一个class中有2个同步语句交错;示例:
我用这些简单的方法和两个锁对象做了一个 class:
public class Locker1 {
private Object lock1= new Object();
private Object lock2= new Object();
public void printL1() {
synchronized(lock1) {
for(int i=0; i<50;i++) {
System.out.println(i);
}
}
}
public void printL2() {
synchronized(lock2) {
for(int i=0; i<50;i++) {
System.out.println("-"+i);
}
}
}
}
我创建了两个不同的线程,它们只调用 printL1
和 printL2
,在我的理解中,我认为因为这是两个不同的锁,所以我会看到交替打印正数和负数,因为并发是可能的,但我尝试了很多次 printL2
总是完全发生在 printL1
之后,不是一次我看到正数之间的负数,我是不是在同步时遗漏了什么?
这是剩余的代码
public class ThreadA extends Thread {
private Locker1 l1;
public ThreadA(Locker1 l1) {
this.l1=l1;
}
public void run() {
l1.printL1();
}
}
public class ThreadB extends Thread {
private Locker1 l1;
public ThreadB(Locker1 l1) {
this.l1=l1;
}
public void run() {
l1.printL2();
}
}
和主要 class:
public class Main {
public static void main(String[] args) {
Locker1 l1=new Locker1();
ThreadA tA=new ThreadA(l1);
ThreadB tB=new ThreadB(l1);
tA.start();
tB.start();
}
}
交织如预期发生;仅进行 50 次迭代就很难看到,因此进行更多次迭代可以显示出来
你对线程和锁的理解是正确的。由于 Locker1.printL1()
和 Locker1.printL2()
将锁授予不同的对象,一个线程访问 Locker1.printL1()
而另一个线程访问 Locker1.printL2()
不应相互阻塞。
您在 printL1 之后看到完整的 printL2 结果的原因是 CPU 的工作太少了。 50 次迭代只需几分之一毫秒即可完成。在需要 context switch 之前,任务已完成。
让任务休眠一小段时间,您可以看到线程的产出情况。
public class Locker1 {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void printL1() {
synchronized (lock1) {
for (int i = 0; i < 50; i++) {
System.out.println(i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void printL2() {
synchronized (lock2) {
for (int i = 0; i < 50; i++) {
System.out.println("-" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
输出:
0
-0
1
-1
2
-2
3
-3
4
-4
5
-5
6
-6
7
-7
8
-8
9
-9
10
-10
11
-11
12
-12
13
-13
14
-14
15
-15
16
-16
17
-17
18
-18
19
-19
20
-20
21
-21
22
-22
-23
23
24
-24
25
-25
26
-26
27
-27
28
-28
29
-29
30
-30
31
-31
32
-32
33
-33
34
-34
35
-35
36
-36
37
-37
38
-38
39
-39
40
-40
41
-41
42
-42
43
-43
44
-44
45
-45
46
-46
47
-47
48
-48
49
-49