Java synchronized instance member doesn't work in a nested way
When programming with Java synchronized, I happend to find a usage which doesn't work as I expect. That is, in thread A, it accesses instance member (content) inside two nested synchronized blocks:
synchronized(this){
synchronized (content) {content = str;}
}
while in thread B, it accesses the same content in only one synchronized block:
synchronized (content) {content = str;}
I expected this can work as a normal usage of
synchronized (content) {content = str;}
however, it doesn't. It works as there is no synchronized.
The complete code and logs are as following:
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 {
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());
/*try {
} catch (Exception e) {
e.printStackTrace();
}*/
}
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());
/*try {
} catch (Exception 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);
}
}
Logs:
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
Why doesn't this happen?
java multithreading synchronized
|
show 1 more comment
When programming with Java synchronized, I happend to find a usage which doesn't work as I expect. That is, in thread A, it accesses instance member (content) inside two nested synchronized blocks:
synchronized(this){
synchronized (content) {content = str;}
}
while in thread B, it accesses the same content in only one synchronized block:
synchronized (content) {content = str;}
I expected this can work as a normal usage of
synchronized (content) {content = str;}
however, it doesn't. It works as there is no synchronized.
The complete code and logs are as following:
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 {
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());
/*try {
} catch (Exception e) {
e.printStackTrace();
}*/
}
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());
/*try {
} catch (Exception 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);
}
}
Logs:
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
Why doesn't this happen?
java multithreading synchronized
2
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
1
considersynchronized (content) { content = str;
// Strings are immutatable - what you arelocking
on has changed
– Scary Wombat
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create aSynConcent
you create a new string. That won't work.
– markspace
Nov 13 '18 at 6:40
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45
|
show 1 more comment
When programming with Java synchronized, I happend to find a usage which doesn't work as I expect. That is, in thread A, it accesses instance member (content) inside two nested synchronized blocks:
synchronized(this){
synchronized (content) {content = str;}
}
while in thread B, it accesses the same content in only one synchronized block:
synchronized (content) {content = str;}
I expected this can work as a normal usage of
synchronized (content) {content = str;}
however, it doesn't. It works as there is no synchronized.
The complete code and logs are as following:
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 {
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());
/*try {
} catch (Exception e) {
e.printStackTrace();
}*/
}
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());
/*try {
} catch (Exception 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);
}
}
Logs:
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
Why doesn't this happen?
java multithreading synchronized
When programming with Java synchronized, I happend to find a usage which doesn't work as I expect. That is, in thread A, it accesses instance member (content) inside two nested synchronized blocks:
synchronized(this){
synchronized (content) {content = str;}
}
while in thread B, it accesses the same content in only one synchronized block:
synchronized (content) {content = str;}
I expected this can work as a normal usage of
synchronized (content) {content = str;}
however, it doesn't. It works as there is no synchronized.
The complete code and logs are as following:
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 {
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());
/*try {
} catch (Exception e) {
e.printStackTrace();
}*/
}
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());
/*try {
} catch (Exception 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);
}
}
Logs:
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
Why doesn't this happen?
java multithreading synchronized
java multithreading synchronized
edited Nov 13 '18 at 6:53
Mureinik
180k22130199
180k22130199
asked Nov 13 '18 at 6:30
Michael Wang
183
183
2
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
1
considersynchronized (content) { content = str;
// Strings are immutatable - what you arelocking
on has changed
– Scary Wombat
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create aSynConcent
you create a new string. That won't work.
– markspace
Nov 13 '18 at 6:40
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45
|
show 1 more comment
2
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
1
considersynchronized (content) { content = str;
// Strings are immutatable - what you arelocking
on has changed
– Scary Wombat
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create aSynConcent
you create a new string. That won't work.
– markspace
Nov 13 '18 at 6:40
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45
2
2
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
1
1
consider
synchronized (content) { content = str;
// Strings are immutatable - what you are locking
on has changed– Scary Wombat
Nov 13 '18 at 6:40
consider
synchronized (content) { content = str;
// Strings are immutatable - what you are locking
on has changed– Scary Wombat
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create a
SynConcent
you create a new string. That won't work.– markspace
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create a
SynConcent
you create a new string. That won't work.– markspace
Nov 13 '18 at 6:40
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45
|
show 1 more comment
1 Answer
1
active
oldest
votes
synchronized
applies to an object, not a name of a variable. You enter the synchronized
block by locking content
, but then in the block, you assign a different object to it. The next time you try to synchronize content
you'll be synchronizing different object, so the previously held lock won't interfere with it.
If you use a mutable object, such as a StringBuilder
and change its data instead, you'll see the behavior you expect:
synchronized (content) {
content.setLength(0); // Remove the old content
content.append(str); // Set the new content
// Rest of the code...
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you writesynchronized (foo) { ... }
thenfoo
should be afinal
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.
– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275060%2fjava-synchronized-instance-member-doesnt-work-in-a-nested-way%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
synchronized
applies to an object, not a name of a variable. You enter the synchronized
block by locking content
, but then in the block, you assign a different object to it. The next time you try to synchronize content
you'll be synchronizing different object, so the previously held lock won't interfere with it.
If you use a mutable object, such as a StringBuilder
and change its data instead, you'll see the behavior you expect:
synchronized (content) {
content.setLength(0); // Remove the old content
content.append(str); // Set the new content
// Rest of the code...
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you writesynchronized (foo) { ... }
thenfoo
should be afinal
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.
– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
add a comment |
synchronized
applies to an object, not a name of a variable. You enter the synchronized
block by locking content
, but then in the block, you assign a different object to it. The next time you try to synchronize content
you'll be synchronizing different object, so the previously held lock won't interfere with it.
If you use a mutable object, such as a StringBuilder
and change its data instead, you'll see the behavior you expect:
synchronized (content) {
content.setLength(0); // Remove the old content
content.append(str); // Set the new content
// Rest of the code...
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you writesynchronized (foo) { ... }
thenfoo
should be afinal
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.
– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
add a comment |
synchronized
applies to an object, not a name of a variable. You enter the synchronized
block by locking content
, but then in the block, you assign a different object to it. The next time you try to synchronize content
you'll be synchronizing different object, so the previously held lock won't interfere with it.
If you use a mutable object, such as a StringBuilder
and change its data instead, you'll see the behavior you expect:
synchronized (content) {
content.setLength(0); // Remove the old content
content.append(str); // Set the new content
// Rest of the code...
synchronized
applies to an object, not a name of a variable. You enter the synchronized
block by locking content
, but then in the block, you assign a different object to it. The next time you try to synchronize content
you'll be synchronizing different object, so the previously held lock won't interfere with it.
If you use a mutable object, such as a StringBuilder
and change its data instead, you'll see the behavior you expect:
synchronized (content) {
content.setLength(0); // Remove the old content
content.append(str); // Set the new content
// Rest of the code...
answered Nov 13 '18 at 6:49
Mureinik
180k22130199
180k22130199
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you writesynchronized (foo) { ... }
thenfoo
should be afinal
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.
– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
add a comment |
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you writesynchronized (foo) { ... }
thenfoo
should be afinal
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.
– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
That's right. I modified the example code and it works correctly now.
– Michael Wang
Nov 13 '18 at 9:41
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
This is really a good lesson, as it often uses immutatable variables, e.g. string.
– Michael Wang
Nov 13 '18 at 9:59
2
2
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you write
synchronized (foo) { ... }
then foo
should be a final
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.– Solomon Slow
Nov 13 '18 at 14:53
It might be worth pointing out that this mistake can be avoided by always following a simple rule: If you write
synchronized (foo) { ... }
then foo
should be a final
variable. If the compiler won't let you do that, then you're either doing something very tricky, or else you're making a mistake. And since "tricky" does not usually mean "good", it's usually best to just follow the rule.– Solomon Slow
Nov 13 '18 at 14:53
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
@SolomonSlow Good, a simple but useful rule
– Michael Wang
Nov 14 '18 at 1:32
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
BTW, another solution is, to add a flag (e.g. an integer) and synchrolize it wherever accessing these immutable variables, as changing these immutable variables to mutable ones might be annoying or impossible sometimes.
– Michael Wang
Nov 15 '18 at 2:05
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275060%2fjava-synchronized-instance-member-doesnt-work-in-a-nested-way%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
It's not clear what you're asking. Is there a problem? What's the expected result? What's the actual result?
– Charlie
Nov 13 '18 at 6:36
1
consider
synchronized (content) { content = str;
// Strings are immutatable - what you arelocking
on has changed– Scary Wombat
Nov 13 '18 at 6:40
Probably because none of those locks are common. You are synchronizing on different objects. Each time you create a
SynConcent
you create a new string. That won't work.– markspace
Nov 13 '18 at 6:40
@Charlie, it's expected to synchrolize the instance member content.
– Michael Wang
Nov 13 '18 at 9:43
@ScaryWombat Correct.
– Michael Wang
Nov 13 '18 at 9:45