关于Java synchronized,网上博文对主要概念都解释的很清楚,但对锁对象和锁对象的非静态成员变量的区别,或者没有提到,或者讲述的不是特别清晰、深刻。
根据本人的理解和实验效果,我认为Java synchronized的主要用法分三种:
本文对第1种用法不做讨论,仅讨论后两种用法的区别。
实验环境:win10 + intelliJ
public class JavaSync {
public static void main(String[] args) {
SyncContent syncContent = new SyncContent("JavaSync");
ThreadA a = new ThreadA(syncContent);
a.setName("A");
a.start();
ThreadB b = new ThreadB(syncContent);
b.setName("B");
b.start();
ThreadC c = new ThreadC(syncContent);
c.setName("C");
c.start();
}
}
class SyncContent {
String content = new String();
public SyncContent(String content){
this.content = content;
}
synchronized public void syncFunc(String str){
try {
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content new: " + content);
Thread.sleep(2000);
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content final: " + content);
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void syncThis(String str){
synchronized(this) {
try {
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
Thread.sleep(2000);
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void syncVariable(String str) {
synchronized(content) {
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content new: " + content);
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
}
}
}
class ThreadA extends Thread {
private SyncContent syncContent;
private String me = "ThreadA";
public ThreadA(SyncContent syncContent) {
super();
this.syncContent = syncContent;
}
@Override
public void run() {
syncContent.syncThis(me);
}
}
class ThreadB extends Thread {
private SyncContent syncContent;
private String me = "ThreadB";
public ThreadB(SyncContent syncContent) {
super();
this.syncContent = syncContent;
}
@Override
public void run() {
syncContent.syncFunc(me);
}
}
class ThreadC extends Thread {
private SyncContent syncContent;
private String me = "ThreadC";
public ThreadC(SyncContent syncContent) {
super();
this.syncContent = syncContent;
}
@Override
public void run() {
syncContent.syncVariable(me);
}
}
Log如下:
syncThis.Thread: A enter: 1542010389797
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542010389798
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542010389798
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542010391798
syncFunc.Thread: B enter: 1542010391798
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542010393799
从上述log可见:
把syncThis()和syncFunc()函数里嵌套synchronized (content):
public void syncThis(String str){
synchronized(this) {
try {
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
synchronized (content) {
content = str;
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
Thread.sleep(2000);
}
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Log如下:
syncThis.Thread: A enter: 1542012050428
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542012050429
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542012050429
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542012052428
syncFunc.Thread: B enter: 1542012052428
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542012054429
从上述log可见:即使synchronized(this)中嵌套调用synchronized(content),也没有与单独调用synchronized(content)达到同步的效果。原因待研究。(曾猜测是不是Thread.sleep会释放锁,但把sleep换成一个纯做加减乘除运算的耗时函数后,效果也一样。另外,一些文章也讲了sleep并不会释放线程持有的锁。)
另外实验,如果ThreadB的run()里面改成调用syncVariable(me),是可以与ThreadC形成同步的,这个结果符合预期,不列log。
参考:
https://blog.csdn.net/u013142781/article/details/51697672
https://blog.csdn.net/luoweifu/article/details/46613015
https://blog.csdn.net/u010002184/article/details/72566874
https://bbs.csdn.net/topics/390954513
https://blog.csdn.net/zbuger/article/details/51030772
https://blog.csdn.net/YChenFeng/article/details/77427554
Update:
对SyncContent类略做优化调整:给String content添加volatile,更换sleep函数,如下:
class SyncContent {
volatile String content = new String();
public SyncContent(String content) {
this.content = content;
}
private double timeConsuming() {
double a, b, c;
double sum = 0;
for (int i = 1; i < 2000000; i++) {
a = i + sum / ( i * 19);
b = a / 17;
c = b * 23;
sum += (b + c - a) / (a + i);
}
return sum;
}
synchronized public void syncFunc(String str) {
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
synchronized (content) {
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content new: " + content);
//Thread.sleep(2000); // InterruptedException
System.out.println("syncFunc.Thread: dummy result: " + timeConsuming());
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content final: " + content);
}
System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
}
public void syncThis(String str) {
synchronized(this) {
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
synchronized (content) {
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
//Thread.sleep(2000); // InterruptedException
System.out.println("syncThis.Thread: dummy result: " + timeConsuming());
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
}
System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
}
}
public void syncVariable(String str) {
synchronized(content) {
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content old: " + content);
content = str;
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content new: " + content);
System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
}
}
}
Log如下:
syncThis.Thread: A enter: 1542076529822
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542076529823
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542076529824
syncThis.Thread: dummy result: 411764.5149938948
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542076529862
syncFunc.Thread: B enter: 1542076529862
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: dummy result: 411764.5149938948
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542076529897
嵌套synchronized()调用,仍然没有起到同步保护的作用。
反编译SyncContent.class,发现syncThis()中存在两层monitorenter,putfield content也在monitorenter内层,但从log看,并没有真正同步。
$ javap -c SyncContent.class
Compiled from "JavaSync.java"
class SyncContent {
volatile java.lang.String content;
public SyncContent(java.lang.String);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."
4: aload_0
5: new #2 // class java/lang/String
8: dup
9: invokespecial #3 // Method java/lang/String."
12: putfield #4 // Field content:Ljava/lang/String;
15: aload_0
16: aload_1
17: putfield #4 // Field content:Ljava/lang/String;
20: return
public synchronized void syncFunc(java.lang.String);
Code:
0: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #11 // class java/lang/StringBuilder
6: dup
7: invokespecial #12 // Method java/lang/StringBuilder."
10: ldc #13 // String syncFunc.Thread:
12: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
18: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
21: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: ldc #17 // String enter:
26: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
32: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
35: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
38: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
41: aload_0
42: getfield #4 // Field content:Ljava/lang/String;
45: dup
46: astore_2
47: monitorenter
48: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
51: new #11 // class java/lang/StringBuilder
54: dup
55: invokespecial #12 // Method java/lang/StringBuilder."
58: ldc #13 // String syncFunc.Thread:
60: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
66: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
69: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: ldc #22 // String content old:
74: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: aload_0
78: getfield #4 // Field content:Ljava/lang/String;
81: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
84: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
87: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
90: aload_0
91: aload_1
92: putfield #4 // Field content:Ljava/lang/String;
95: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
98: new #11 // class java/lang/StringBuilder
101: dup
102: invokespecial #12 // Method java/lang/StringBuilder."
105: ldc #13 // String syncFunc.Thread:
107: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
110: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
113: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
116: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
119: ldc #23 // String content new:
121: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
124: aload_0
125: getfield #4 // Field content:Ljava/lang/String;
128: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
131: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
134: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
137: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
140: new #11 // class java/lang/StringBuilder
143: dup
144: invokespecial #12 // Method java/lang/StringBuilder."
147: ldc #24 // String syncFunc.Thread: dummy result:
149: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
152: aload_0
153: invokespecial #25 // Method timeConsuming:()D
156: invokevirtual #26 // Method java/lang/StringBuilder.append:(D)Ljava/lang/StringBuilder;
159: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
162: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
165: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
168: new #11 // class java/lang/StringBuilder
171: dup
172: invokespecial #12 // Method java/lang/StringBuilder."
175: ldc #13 // String syncFunc.Thread:
177: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
180: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
183: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
186: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
189: ldc #27 // String content final:
191: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
194: aload_0
195: getfield #4 // Field content:Ljava/lang/String;
198: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
201: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
204: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
207: aload_2
208: monitorexit
209: goto 217
212: astore_3
213: aload_2
214: monitorexit
215: aload_3
216: athrow
217: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
220: new #11 // class java/lang/StringBuilder
223: dup
224: invokespecial #12 // Method java/lang/StringBuilder."
227: ldc #13 // String syncFunc.Thread:
229: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
232: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
235: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
238: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
241: ldc #28 // String exit:
243: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
246: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
249: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
252: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
255: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
258: return
Exception table:
from to target type
48 209 212 any
212 215 212 any
public void syncThis(java.lang.String);
Code:
0: aload_0
1: dup
2: astore_2
3: monitorenter
4: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
7: new #11 // class java/lang/StringBuilder
10: dup
11: invokespecial #12 // Method java/lang/StringBuilder."
14: ldc #29 // String syncThis.Thread:
16: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
22: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
25: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: ldc #17 // String enter:
30: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
36: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
39: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: aload_0
46: getfield #4 // Field content:Ljava/lang/String;
49: dup
50: astore_3
51: monitorenter
52: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
55: new #11 // class java/lang/StringBuilder
58: dup
59: invokespecial #12 // Method java/lang/StringBuilder."
62: ldc #29 // String syncThis.Thread:
64: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
67: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
70: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
73: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
76: ldc #22 // String content old:
78: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
81: aload_0
82: getfield #4 // Field content:Ljava/lang/String;
85: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
88: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
91: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
94: aload_0
95: aload_1
96: putfield #4 // Field content:Ljava/lang/String;
99: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
102: new #11 // class java/lang/StringBuilder
105: dup
106: invokespecial #12 // Method java/lang/StringBuilder."
109: ldc #29 // String syncThis.Thread:
111: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
114: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
117: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
120: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
123: ldc #23 // String content new:
125: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
128: aload_0
129: getfield #4 // Field content:Ljava/lang/String;
132: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
135: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
138: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
141: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
144: new #11 // class java/lang/StringBuilder
147: dup
148: invokespecial #12 // Method java/lang/StringBuilder."
151: ldc #30 // String syncThis.Thread: dummy result:
153: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
156: aload_0
157: invokespecial #25 // Method timeConsuming:()D
160: invokevirtual #26 // Method java/lang/StringBuilder.append:(D)Ljava/lang/StringBuilder;
163: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
166: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
169: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
172: new #11 // class java/lang/StringBuilder
175: dup
176: invokespecial #12 // Method java/lang/StringBuilder."
179: ldc #29 // String syncThis.Thread:
181: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
184: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
187: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
190: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
193: ldc #27 // String content final:
195: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
198: aload_0
199: getfield #4 // Field content:Ljava/lang/String;
202: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
205: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
208: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
211: aload_3
212: monitorexit
213: goto 223
216: astore 4
218: aload_3
219: monitorexit
220: aload 4
222: athrow
223: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
226: new #11 // class java/lang/StringBuilder
229: dup
230: invokespecial #12 // Method java/lang/StringBuilder."
233: ldc #29 // String syncThis.Thread:
235: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
238: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
241: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
244: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
247: ldc #28 // String exit:
249: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
252: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
255: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
258: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
261: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
264: aload_2
265: monitorexit
266: goto 276
269: astore 5
271: aload_2
272: monitorexit
273: aload 5
275: athrow
276: return
Exception table:
from to target type
52 213 216 any
216 220 216 any
4 266 269 any
269 273 269 any
public void syncVariable(java.lang.String);
Code:
0: aload_0
1: getfield #4 // Field content:Ljava/lang/String;
4: dup
5: astore_2
6: monitorenter
7: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
10: new #11 // class java/lang/StringBuilder
13: dup
14: invokespecial #12 // Method java/lang/StringBuilder."
17: ldc #31 // String syncVariable.Thread:
19: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
25: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
28: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
31: ldc #17 // String enter:
33: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
39: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
42: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
45: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
51: new #11 // class java/lang/StringBuilder
54: dup
55: invokespecial #12 // Method java/lang/StringBuilder."
58: ldc #31 // String syncVariable.Thread:
60: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
66: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
69: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: ldc #22 // String content old:
74: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: aload_0
78: getfield #4 // Field content:Ljava/lang/String;
81: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
84: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
87: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
90: aload_0
91: aload_1
92: putfield #4 // Field content:Ljava/lang/String;
95: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
98: new #11 // class java/lang/StringBuilder
101: dup
102: invokespecial #12 // Method java/lang/StringBuilder."
105: ldc #31 // String syncVariable.Thread:
107: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
110: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
113: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
116: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
119: ldc #23 // String content new:
121: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
124: aload_0
125: getfield #4 // Field content:Ljava/lang/String;
128: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
131: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
134: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
137: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
140: new #11 // class java/lang/StringBuilder
143: dup
144: invokespecial #12 // Method java/lang/StringBuilder."
147: ldc #31 // String syncVariable.Thread:
149: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
152: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
155: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
158: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
161: ldc #28 // String exit:
163: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
166: invokestatic #18 // Method java/lang/System.currentTimeMillis:()J
169: invokevirtual #19 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
172: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
175: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
178: aload_2
179: monitorexit
180: goto 188
183: astore_3
184: aload_2
185: monitorexit
186: aload_3
187: athrow
188: return
Exception table:
from to target type
7 180 183 any
183 186 183 any
}
该问题待解。
更新(原因已找到):
原因:content = str; 这步操作会导致content被赋值给一个新的string对象,所以Thread A 和 Thread C synchronized(content)的对象是不同的,因此没有形成同步保护。
解决办法:
修改content的类型,如把String content 改成 可修改的StringBuilder类型。
或者,另外增加一个不变的对象flag,先同步synchronized(flag),再设置content的值。