
Hello, I am hesitating between the two following styles of synchronization. First style, with one lengthy synchronization block synchronize(x) { shortOpA(); shortOpB(); shortOpC(); shortOpD(); longOp(); } Second style, with shorter but more numerous synchronization blocks synchronize(a) { shortOpA(); } synchronize(b) { shortOpB(); } shortOpC(); // no need for synchronization shortOpD(); // no need for synchronization synchronize(x) { longOp(); } Let us assume that longOp() takes about 5 times longer than shortOp_N() to complete. Moreover, all operations are self contained, with no further synchronization (locking) dependencies to external code. I wonder which style is better. The first style is simpler to understand, because there is just one synchronization block. However, the monitor is held for a longer period. In the second style, there are more locks, so the code may be harder to follow but each lock is held for a shorter period. Surprisingly enough, tests (with 10 threads) show that performance is slightly better with the first style. Am I splitting hairs? -- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Ceki Gulcu wrote:
Hello,
I am hesitating between the two following styles of synchronization.
First style, with one lengthy synchronization block
synchronize(x) { shortOpA(); shortOpB(); shortOpC(); shortOpD(); longOp(); }
Second style, with shorter but more numerous synchronization blocks
synchronize(a) { shortOpA(); }
synchronize(b) { shortOpB(); }
shortOpC(); // no need for synchronization shortOpD(); // no need for synchronization
synchronize(x) { longOp(); }
Ideally, synchronization should be done like this, if reordering is possible: shortOpC(); shortOpD(); synchronize(x) { shortOpA(); shortOpB(); longOp(); } The longer a lock is held, the more likely starvation might occur. I'd obviously vote for fair locking instead of synchronized since the additional time spent obtaining the lock is much smaller than the time blocked threads are potentially waiting to be able to work again, as I've shown in http://jira.qos.ch/browse/LBCLASSIC-140?focusedCommentId=11178#action_11178
Let us assume that longOp() takes about 5 times longer than shortOp_N() to complete. Moreover, all operations are self contained, with no further synchronization (locking) dependencies to external code.
I wonder which style is better. The first style is simpler to understand, because there is just one synchronization block. However, the monitor is held for a longer period. In the second style, there are more locks, so the code may be harder to follow but each lock is held for a shorter period.
Surprisingly enough, tests (with 10 threads) show that performance is slightly better with the first style.
It's not *that* surprising for me since synchronization of any kind includes an additional overhead incl. the decision which thread may obtain the lock and which will have to wait some more.
Am I splitting hairs?
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs. Regards, Joern.

Joern Huxhorn wrote:
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs.
While open to further investigation and new data, evidence collected indicates that threads in Sun's JDK on multi-core CPU on Linux as well as other platforms can make other threads starve but that is *not* a logback issue. Moreover, it would be unfair to penalize *all* logback users using fair locking which is much slower than synchronization or unfair locks. As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data?
Regards, Joern.
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

I meant to say: evidence collected *thus far* indicates that... Ceki Gulcu wrote:
Joern Huxhorn wrote:
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs.
While open to further investigation and new data, evidence collected indicates that threads in Sun's JDK on multi-core CPU on Linux as well as other platforms can make other threads starve but that is *not* a logback issue. Moreover, it would be unfair to penalize *all* logback users using fair locking which is much slower than synchronization or unfair locks.
As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data?
Regards, Joern.
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Ceki Gulcu wrote:
Joern Huxhorn wrote:
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs.
While open to further investigation and new data, evidence collected indicates that threads in Sun's JDK on multi-core CPU on Linux as well as other platforms can make other threads starve but that is *not* a logback issue. Moreover, it would be unfair to penalize *all* logback users using fair locking which is much slower than synchronization or unfair locks.
I copied your results over from your test for the sake of discussion: java.runtime.version = 1.6.0_11-b03 java.vendor = Sun Microsystems Inc. java.version = 1.6.0_11 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 139698775, or 35 nanos per cycle Unfair: 87028802, or 57 nanos per cycle Fair: 4106449, or 1217 nanos per cycle java.runtime.version = jvmxa6460-20081105_25433 java.vendor = IBM Corporation java.version = 1.6.0 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 356946629, or 14 nanos per cycle Unfair: 91892449, or 54 nanos per cycle Fair: 7380308, or 677 nanos per cycle So yes, the locking itself is significantly slower. The following numbers are the max amount of wasted time of my example app: 2959018000 synchronized 2078606000 unfair lock 27691000 fair lock The maximum wasted time of all threads is ~100 times smaller in case of the fair lock!! This means that the overall system is running *waaay* smoother... regardless of the additional nanos spent for the fair lock. The main problem is that *every* CPU has to access the appender, degrading multi-core-systems to semi-single-core. Minimizing the amount of time a thread (and therefore one of the other cores) has to wait is crucial.
As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data? Yes, I do, but performance was absolutely sufficient on a single-core system - which is quite ironic. Let's just forget about my appender for the moment. The behavior is similar but less dramatic in case of FileAppender.
Regards, Joern.

Joern Huxhorn wrote:
Ceki Gulcu wrote:
Joern Huxhorn wrote:
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs. While open to further investigation and new data, evidence collected indicates that threads in Sun's JDK on multi-core CPU on Linux as well as other platforms can make other threads starve but that is *not* a logback issue. Moreover, it would be unfair to penalize *all* logback users using fair locking which is much slower than synchronization or unfair locks.
I copied your results over from your test for the sake of discussion: java.runtime.version = 1.6.0_11-b03 java.vendor = Sun Microsystems Inc. java.version = 1.6.0_11 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 139698775, or 35 nanos per cycle Unfair: 87028802, or 57 nanos per cycle Fair: 4106449, or 1217 nanos per cycle
java.runtime.version = jvmxa6460-20081105_25433 java.vendor = IBM Corporation java.version = 1.6.0 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 356946629, or 14 nanos per cycle Unfair: 91892449, or 54 nanos per cycle Fair: 7380308, or 677 nanos per cycle
So yes, the locking itself is significantly slower.
The following numbers are the max amount of wasted time of my example app: 2959018000 synchronized 2078606000 unfair lock 27691000 fair lock The maximum wasted time of all threads is ~100 times smaller in case of the fair lock!! This means that the overall system is running *waaay* smoother... regardless of the additional nanos spent for the fair lock. The main problem is that *every* CPU has to access the appender, degrading multi-core-systems to semi-single-core. Minimizing the amount of time a thread (and therefore one of the other cores) has to wait is crucial.
Joern, The numbers regarding *wasted* time above do not bring any new information. Assuming there is thread starvation, those starving threads will sit by idly. There is no new information there. It is just stating the obvious. The question is why there is starvation. In a real-world application, threads will be waiting on several monitors so that the starvation problem is less likely to occur. In other words, LockingInJava is not or may not be so a representative of reality.
As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data?
Yes, I do, but performance was absolutely sufficient on a single-core system - which is quite ironic. Let's just forget about my appender for the moment. The behavior is similar but less dramatic in case of FileAppender.
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine. Collecting caller data might just cause waiting threads to be parked at the kernel instead of spun.
Regards, Joern.
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Ceki Gulcu skrev:
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine.
How would you get an IBM JVM for Solaris? A trial of WebSphere? -- Thorbjørn Ravn Andersen "...plus... Tubular Bells!"

Thorbjoern Ravn Andersen wrote:
Ceki Gulcu skrev:
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine.
How would you get an IBM JVM for Solaris? A trial of WebSphere?
I have no idea. It was a stupid suggestion. On the other hand, my remark about caller data is potentially right on target. -- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Ceki Gulcu skrev:
Thorbjoern Ravn Andersen wrote:
Ceki Gulcu skrev:
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine.
How would you get an IBM JVM for Solaris? A trial of WebSphere?
I have no idea. It was a stupid suggestion. On the other hand, my remark about caller data is potentially right on target.
IBM _has_ a JVM for Solaris. The problem is getting hold of it. Perhaps Jörn has it inhouse already? -- Thorbjørn Ravn Andersen "...plus... Tubular Bells!"

On 02.07.2009, at 19:07, Ceki Gulcu wrote:
Joern Huxhorn wrote:
Ceki Gulcu wrote:
Joern Huxhorn wrote:
Nope, a discussion like that is really necessary because this whole issue is pretty crucial and will essentially decide how well Logback will perform in environments with >1 CPU-cores. This will become more and more important with more cores added in every new CPU generation. The more cores are present, the more relevant the issue of unfairness will become, since waiting threads will mean idling CPUs. While open to further investigation and new data, evidence collected indicates that threads in Sun's JDK on multi-core CPU on Linux as well as other platforms can make other threads starve but that is *not* a logback issue. Moreover, it would be unfair to penalize *all* logback users using fair locking which is much slower than synchronization or unfair locks.
I copied your results over from your test for the sake of discussion: java.runtime.version = 1.6.0_11-b03 java.vendor = Sun Microsystems Inc. java.version = 1.6.0_11 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 139698775, or 35 nanos per cycle Unfair: 87028802, or 57 nanos per cycle Fair: 4106449, or 1217 nanos per cycle java.runtime.version = jvmxa6460-20081105_25433 java.vendor = IBM Corporation java.version = 1.6.0 os.name = Linux os.version = 2.6.25-gentoo-r6 Sync: 356946629, or 14 nanos per cycle Unfair: 91892449, or 54 nanos per cycle Fair: 7380308, or 677 nanos per cycle So yes, the locking itself is significantly slower. The following numbers are the max amount of wasted time of my example app: 2959018000 synchronized 2078606000 unfair lock 27691000 fair lock The maximum wasted time of all threads is ~100 times smaller in case of the fair lock!! This means that the overall system is running *waaay* smoother... regardless of the additional nanos spent for the fair lock. The main problem is that *every* CPU has to access the appender, degrading multi-core-systems to semi-single-core. Minimizing the amount of time a thread (and therefore one of the other cores) has to wait is crucial.
Joern,
The numbers regarding *wasted* time above do not bring any new information. Assuming there is thread starvation, those starving threads will sit by idly. There is no new information there. It is just stating the obvious.
Even if there is no starvation that completely prevents access of any other threads, there is still an impact of logging on the execution of multiple threads. Threads are waiting longer than necessary in case of unfair locks. And that's my whole point. 1ms delay: 2959018000 synchronized 2078606000 unfair lock 27691000 fair lock 10ms delay: 7592208000 synchronized 9756758000 unfair lock 12816000 fair lock "Wasted time" means that a processor core isn't working. The higher this value is the less optimal an application is scaling on n-core- systems. And this is *only* caused by unfair locking of the logging system. I'm honestly baffled that nobody else seems to care. Beside all that, I have the opinion that logging should happen in the order that an application would like to log. Thread A tries to log "A". Thread B tries to log "B". Thread C tries to log "C". Thread A tries to log "A2". Should always log A,B,C,A2 and not A,A2,C,B, which can be the case with unfair locking. I'd consider this a bug.
The question is why there is starvation. In a real-world application, threads will be waiting on several monitors so that the starvation problem is less likely to occur. In other words, LockingInJava is not or may not be so a representative of reality.
That's not true, the only monitor that needs to be acquired is the one on (or inside) the appender.
As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data?
Yes, I do, but performance was absolutely sufficient on a single-core system - which is quite ironic. Let's just forget about my appender for the moment. The behavior is similar but less dramatic in case of FileAppender.
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine.
I have the exact same issue with the Apple implementation of Java which, sadly, isn't a real Sun JVM. I can't post the config right now but it's seriously unspectacular. Nothing special in there.
Collecting caller data might just cause waiting threads to be parked at the kernel instead of spun.
Regardless of the cause, either collecting the caller data or not, such a behavior simply mustn't happen in my books. Regards, Joern.

Joern Huxhorn wrote:
Joern,
The numbers regarding *wasted* time above do not bring any new information. Assuming there is thread starvation, those starving threads will sit by idly. There is no new information there. It is just stating the obvious.
Even if there is no starvation that completely prevents access of any other threads, there is still an impact of logging on the execution of multiple threads.
Threads are waiting longer than necessary in case of unfair locks. And that's my whole point.
1ms delay: 2959018000 synchronized 2078606000 unfair lock 27691000 fair lock
10ms delay: 7592208000 synchronized 9756758000 unfair lock 12816000 fair lock
With all due respect, as I see things, the figures given by TimeWasted application attached to LBCLASSIC-140 [1] are essentially meaningless because TimeWasted measures the time spent (or wasted) waiting to access a lock. Here is the relevant code code: public static class WastedTimeSynchronizedRunnable implements Runnable { public void run() { for(;;) { ... long wasted=System.nanoTime(); synchronized(lockObject) { counter++; } wasted=System.nanoTime()-wasted; } } } public static class WastedTimeSynchronizedRunnable implements Runnable { public void run() for(;;) { ... omitted code lock.lock(); try { counter++; } finally { lock.unlock(); } wasted=System.nanoTime()-wasted; } } } We all agree that when a single thread grabs the CPU while others threads starve, the other threads get nothing or very little done, but that is just the definition of thread starvation. Zero surprise = zero new information. [1] http://jira.qos.ch/browse/LBCLASSIC-140
"Wasted time" means that a processor core isn't working. The higher this value is the less optimal an application is scaling on n-core-systems. And this is *only* caused by unfair locking of the logging system. I'm honestly baffled that nobody else seems to care.
I estimate that I've already spent over 3 man days on this question. I would not have spent this time if I did not care. Other participants also seem quite interested, some of them might even silently agree with you. :-)
Beside all that, I have the opinion that logging should happen in the order that an application would like to log.
Thread A tries to log "A". Thread B tries to log "B". Thread C tries to log "C". Thread A tries to log "A2".
Should always log A,B,C,A2 and not A,A2,C,B, which can be the case with unfair locking. I'd consider this a bug.
Come on. You can't just ignore the way the JVM handles time-slicing.
That's not true, the only monitor that needs to be acquired is the one on (or inside) the appender.
A real-world application, contrary to the small test applications such as TimeWasted, SynchronizedVsFairLock and others, is likely to have dependencies on resources other than logging, e.g. a data base, network connection etc. Thus, under "normal" conditions, thread starvation is much less likely to occur. The thread hogging a logging-related lock is eventually bound to wait on another resource in which time the threads waiting to obtain the logging-related lock will be able to obtain it. BTW, invoking Thread.yield() is another way to force a thread to let other threads run. All I am saying is that a "normal" application will have these Thread.yield() points naturally and transparently on its execution path.
As a side note, and if my memory serves me well, you gather caller data for every log call which can have significant impact on performance. Are you collecting caller data?
Yes, I do, but performance was absolutely sufficient on a single-core system - which is quite ironic. Let's just forget about my appender for the moment. The behavior is similar but less dramatic in case of FileAppender.
Interesting. Could you post your config file? When you say less dramatic, do you mean the behavior of your application in production? I guess it could be infeasible to try running your application with IBM's JDK on your 4-core Solaris machine.
I have the exact same issue with the Apple implementation of Java which, sadly, isn't a real Sun JVM. I can't post the config right now but it's seriously unspectacular. Nothing special in there.
What is unspectacular? The way the JVM distributes the lock among competing threads?
Collecting caller data might just cause waiting threads to be parked at the kernel instead of spun.
Regardless of the cause, either collecting the caller data or not, such a behavior simply mustn't happen in my books.
I am trying to solve this issue the best I can. Insisting on fair locks without exploring alternatives will not get us very far. Given that collecting caller data is pretty expensive, it might influence the way the JVM treats threads waiting for a lock (spinning vs parking) which mat be the cause behind the starvation effects you are seeing. Could you please try to set up logging without CallerData in your application and see what happens? While I agree with you that the logging framework should not have undesired side-effects such as thread starvation, a java logging framework is bound by the limitations of the JVM under which it is executing. It's *not* logback's responsibility to fix the host JVM. Also note that Sun excepted my bug report on this issue. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6855216 Your request for fair locking in appenders is not unreasonable. However, it will cause a measurable slow down in a large number of cases. It also feels like fixing the JVM. So, I need more evidence before going down the path of fair locking. Best regards,
Regards, Joern.
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Ceki Gulcu skrev:
Also note that Sun excepted my bug report on this issue. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6855216
I see that it is registered as a wontfix bug and linked to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4985566 which says that "The JVM does not entirely isolate java threads from the scheduling properites of the underlying operating system." and that you should use the concurrent utils instead. I have not followed this closely, but is that an option?
Your request for fair locking in appenders is not unreasonable. However, it will cause a measurable slow down in a large number of cases. It also feels like fixing the JVM. So, I need more evidence before going down the path of fair locking. If the conclusion is that "it depends" how to do this right, perhaps it should be configurable?
-- Thorbjørn Ravn Andersen "...plus... Tubular Bells!"

Thorbjoern Ravn Andersen wrote:
Ceki Gulcu skrev:
Also note that Sun excepted my bug report on this issue. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6855216
I see that it is registered as a wontfix bug
As far as I can see bug 6855216 is in state "1-Dispatched" whatever that means.
I have not followed this closely, but is that an option?
Your request for fair locking in appenders is not unreasonable. However, it will cause a measurable slow down in a large number of cases. It also feels like fixing the JVM. So, I need more evidence before going down the path of fair locking.
If the conclusion is that "it depends" how to do this right, perhaps it should be configurable?
FileAppender (and co) in svn trunk has much finer grain locking. I am thus hoping that this problem will be "transparently" solved in logback 0.9.16 when it is released. -- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

I would recommend the second, largely because some of the things that are being synchronized might be able to be converted to constructs that don't require synchronization. Furthermore, as long as you are holding a lock over such a wide scope you run the risk of something being inserted into that synchronized block that does something that raises the possibility of a deadlock. I would comment more but my wife is in the hospital for the next few days so I won't have much time until after the weekend. Ralph On Jul 2, 2009, at 12:39 AM, Ceki Gulcu wrote:
Hello,
I am hesitating between the two following styles of synchronization.
First style, with one lengthy synchronization block
synchronize(x) { shortOpA(); shortOpB(); shortOpC(); shortOpD(); longOp(); }
Second style, with shorter but more numerous synchronization blocks
synchronize(a) { shortOpA(); }
synchronize(b) { shortOpB(); }
shortOpC(); // no need for synchronization shortOpD(); // no need for synchronization
synchronize(x) { longOp(); }
Let us assume that longOp() takes about 5 times longer than shortOp_N() to complete. Moreover, all operations are self contained, with no further synchronization (locking) dependencies to external code.
I wonder which style is better. The first style is simpler to understand, because there is just one synchronization block. However, the monitor is held for a longer period. In the second style, there are more locks, so the code may be harder to follow but each lock is held for a shorter period.
Surprisingly enough, tests (with 10 threads) show that performance is slightly better with the first style.
Am I splitting hairs?
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch _______________________________________________ logback-dev mailing list logback-dev@qos.ch http://qos.ch/mailman/listinfo/logback-dev

Ralph Goers wrote:
I would recommend the second, largely because some of the things that are being synchronized might be able to be converted to constructs that don't require synchronization. Furthermore, as long as you are holding a lock over such a wide scope you run the risk of something being inserted into that synchronized block that does something that raises the possibility of a deadlock.
Agreed.
I would comment more but my wife is in the hospital for the next few days so I won't have much time until after the weekend.
My best wishes to your wife.
Ralph -- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

I agree with Ralph: try to keep the locks as briefly as possible. Because a) it could improve scalability b) the reason that Joern gives c) if there ever is a need to change it, making synchonized blocks bigger is probably easier than trying to make them smaller I definitely agree about not penalizing *all* users with fair locks. from Java Concurrency In Practice: "While shrinking synchronized blocks can improve scalability, a synchronizedblock can be too small. - operations that need to be atomic (such updating multiple variables that participate in an invariant) must be contained in a single synchronized block. And because the cost of synchronization is nonzero, breaking one synchronized block into multiple synchronized blocks (correctness permitting) at some point becomes counterproductive in terms of performance.[9]<http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html#ch11fn09>The ideal balance is of course platform-dependent, but in practice it makes sense to worry about the size of a synchronized block only when you can move "substantial" computation or blocking operations out of it. [9] If the JVM performs lock coarsening, it may undo the splitting of synchronized blocks anyway." http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html Maarten On Thu, Jul 2, 2009 at 4:37 PM, Ceki Gulcu <ceki@qos.ch> wrote:
Ralph Goers wrote:
I would recommend the second, largely because some of the things that are being synchronized might be able to be converted to constructs that don't require synchronization. Furthermore, as long as you are holding a lock over such a wide scope you run the risk of something being inserted into that synchronized block that does something that raises the possibility of a deadlock.
Agreed.
I would comment more but my wife is in the hospital for the next few days
so I won't have much time until after the weekend.
My best wishes to your wife.
Ralph
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch _______________________________________________ logback-dev mailing list logback-dev@qos.ch http://qos.ch/mailman/listinfo/logback-dev

Thank you for this link. Maarten Bosteels wrote:
I agree with Ralph: try to keep the locks as briefly as possible. Because a) it could improve scalability
In the general case, yes.
b) the reason that Joern gives
The statement that "the longer a lock is held, the more likely starvation might occur" is only true at a single singularity point chosen by the JVM. The JVM will measure thread contention per lock. It will either spin a thread waiting on a monitor or park it at the level of the OS/kernel. Very short living locks will be spinned by default, while locks with longer durations will be parked. Thus, there is a singularity point where the JVM prefer parking over spinning. For more detail, see Dave Dice's comments in my blog [1]. Here is a relevant excerpt: Regarding Thread.sleep(1) vs sleep(10), sleep times are quantized differently on various platforms. On some systems sleep(1) will round up to at least 10 msecs. I'm assuming you're running on a newer linux kernel (tickless or 1000HZ) or something similar. With a longer sleep period (10 msecs) it'll almost be the case that the competing threads will have given up on spinning and blocked in the kernel. When the lock holder releases the lock it'll select an "heir presumptive" and unpark that thread. But in your case the dominating thread will try to reacquire the lock before the wakee manages to become active. With shorter sleep times it's more likely that the contending threads will be spinning instead of blocked, in which case they can immediately pounce on the lock. IBM's JDK has a very different time-slicing behavior. At present time, I consider LBCLASSIC-140 to be an issue with Sun's JVM. However, cognizant of the fact that Sun is the dominant JVM "vendor", I am willing to reconsider but only if new evidence can be brought to bear. [1] http://ceki.blogspot.com/2009/06/biased-locking-in-java-se-60.html
c) if there ever is a need to change it, making synchonized blocks bigger is probably easier than trying to make them smaller
Sure.
I definitely agree about not penalizing *all* users with fair locks.
from Java Concurrency In Practice:
"While shrinking synchronized blocks can improve scalability, a synchronized block can be too small. - operations that need to be atomic (such updating multiple variables that participate in an invariant) must be contained in a single synchronized block. And because the cost of synchronization is nonzero, breaking one synchronized block into multiple synchronized blocks (correctness permitting) at some point becomes counterproductive in terms of performance.^[9] <http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html#ch11fn09> The ideal balance is of course platform-dependent, but in practice it makes sense to worry about the size of a synchronized block only when you can move "substantial" computation or blocking operations out of it.
^[9] If the JVM performs lock coarsening, it may undo the splitting of synchronized blocks anyway."
http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html
Thank you for this link and the quote. As for JVM lock coarsening, I think it will do so if it is the same lock that is being held and released. AFAIK, the JVM won't/can't coarsen distinct locks.
Maarten -- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

On Thu, Jul 2, 2009 at 6:30 PM, Ceki Gulcu <ceki@qos.ch> wrote:
Thank you for this link.
Maarten Bosteels wrote:
I agree with Ralph: try to keep the locks as briefly as possible. Because a) it could improve scalability
In the general case, yes.
b) the reason that Joern gives
oops, I meant: for the reason that *Ralph* gave which was: "largely because some of the things that are being synchronized might be able to be converted to constructs that don't require synchronization. Furthermore, as long as you are holding a lock over such a wide scope you run the risk of something being inserted into that synchronized block that does something that raises the possibility of a deadlock." sorry for the confusion. Maarten
The statement that "the longer a lock is held, the more likely starvation might occur" is only true at a single singularity point chosen by the JVM. The JVM will measure thread contention per lock. It will either spin a thread waiting on a monitor or park it at the level of the OS/kernel. Very short living locks will be spinned by default, while locks with longer durations will be parked. Thus, there is a singularity point where the JVM prefer parking over spinning. For more detail, see Dave Dice's comments in my blog [1]. Here is a relevant excerpt:
Regarding Thread.sleep(1) vs sleep(10), sleep times are quantized differently on various platforms. On some systems sleep(1) will round up to at least 10 msecs. I'm assuming you're running on a newer linux kernel (tickless or 1000HZ) or something similar. With a longer sleep period (10 msecs) it'll almost be the case that the competing threads will have given up on spinning and blocked in the kernel. When the lock holder releases the lock it'll select an "heir presumptive" and unpark that thread. But in your case the dominating thread will try to reacquire the lock before the wakee manages to become active. With shorter sleep times it's more likely that the contending threads will be spinning instead of blocked, in which case they can immediately pounce on the lock.
IBM's JDK has a very different time-slicing behavior. At present time, I consider LBCLASSIC-140 to be an issue with Sun's JVM. However, cognizant of the fact that Sun is the dominant JVM "vendor", I am willing to reconsider but only if new evidence can be brought to bear.
[1] http://ceki.blogspot.com/2009/06/biased-locking-in-java-se-60.html
c) if there ever is a need to change it, making synchonized blocks bigger
is probably easier than trying to make them smaller
Sure.
I definitely agree about not penalizing *all* users with fair locks.
from Java Concurrency In Practice:
"While shrinking synchronized blocks can improve scalability, a synchronized block can be too small. - operations that need to be atomic (such updating multiple variables that participate in an invariant) must be contained in a single synchronized block. And because the cost of synchronization is nonzero, breaking one synchronized block into multiple synchronized blocks (correctness permitting) at some point becomes counterproductive in terms of performance.^[9] < http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html#ch11fn09> The ideal balance is of course platform-dependent, but in practice it makes sense to worry about the size of a synchronized block only when you can move "substantial" computation or blocking operations out of it.
^[9] If the JVM performs lock coarsening, it may undo the splitting of synchronized blocks anyway."
http://book.javanb.com/java-concurrency-in-Practice/ch11lev1sec4.html
Thank you for this link and the quote.
As for JVM lock coarsening, I think it will do so if it is the same lock that is being held and released. AFAIK, the JVM won't/can't coarsen distinct locks.
Maarten
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch _______________________________________________ logback-dev mailing list logback-dev@qos.ch http://qos.ch/mailman/listinfo/logback-dev
participants (5)
-
Ceki Gulcu
-
Joern Huxhorn
-
Maarten Bosteels
-
Ralph Goers
-
Thorbjoern Ravn Andersen