tag:blogger.com,1999:blog-865923359735383241.post6881822709137962377..comments2023-10-29T07:27:09.012-06:00Comments on Ccna final exam - java, php, javascript, ios, cshap all in one: What is the most frequent concurrency issue you"ve encountered in Java?Unknownnoreply@blogger.comBlogger27125tag:blogger.com,1999:blog-865923359735383241.post-61301845699104029512012-06-08T19:28:02.479-06:002012-06-08T19:28:02.479-06:00The dumbest mistake I frequently make is forgettin...The dumbest mistake I frequently make is forgetting to synchronize before calling notify() or wait() on an object.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-62982040150864720622012-06-08T19:27:50.860-06:002012-06-08T19:27:50.860-06:00Synchronizing on a string literal or constant defi...Synchronizing on a string literal or constant defined by a string literal is (potentially) a problem as the string literal is interned and will be shared by anyone else in the JVM using the same string literal. I know this problem has come up in application servers and other "container" scenarios. <br /><br />Example:<br /><br />private static final String SOMETHING = "foo";<br /><br />synchronized(SOMETHING) {<br /> //<br />}<br /><br /><br />In this case, anyone using the string "foo" to lock on is sharing the same lock.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-9518337868114538372012-06-08T19:27:46.311-06:002012-06-08T19:27:46.311-06:00Another common 'concurrency' issue is to u...Another common 'concurrency' issue is to use synchronized code when it is not necessary at all. For example I still see programmers using StringBuffer or even java.util.Vector (as method local variables).Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-68421521533831693202012-06-08T19:27:43.869-06:002012-06-08T19:27:43.869-06:00Using a local "new Object()" as mutex.
...Using a local "new Object()" as mutex.<br /><br />synchronized (new Object())<br />{<br /> System.out.println("sdfs");<br />}<br /><br /><br />This is useless.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-60542283062602854822012-06-08T19:27:42.339-06:002012-06-08T19:27:42.339-06:00I encountered a concurrency problem with Servlets,...I encountered a concurrency problem with Servlets, when there are mutable fields which will be setted by each request.<br />But there is only one servlet-instance for all request, so this worked perfectly in a single user environment but when more than one user requested the servlet unpredictable results occured.<br /><br />public class MyServlet implements Servlet{<br /> private Object something;<br /><br /> public void service(ServletRequest request, ServletResponse response)<br /> throws ServletException, IOException{<br /> this.something = request.getAttribute("something");<br /> doSomething();<br /> }<br /><br /> private void doSomething(){<br /> this.something ...<br /> }<br />}Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-81990254643952513122012-06-08T19:27:35.490-06:002012-06-08T19:27:35.490-06:00Unbalanced synchronization, particularly against M...Unbalanced synchronization, particularly against Maps seems to be a fairly common problem. Many people believe that synchronizing on puts to a Map (not a ConcurrentMap, but say a HashMap) and not synchronizing on gets is sufficient. This however can lead to an infinite loop during re-hash. <br /><br />The same problem (partial synchronization) can occur anywhere you have shared state with reads and writes however.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-28913392860634586102012-06-08T19:27:32.634-06:002012-06-08T19:27:32.634-06:00Multiple objects that are lock protected but are c...Multiple objects that are lock protected but are commonly accessed in succession. We've run into a couple of cases where the locks are obtained by different code in different orders, resulting in deadlock.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-12646593974469956762012-06-08T19:27:25.174-06:002012-06-08T19:27:25.174-06:00Starting a thread within the constructor of a clas...Starting a thread within the constructor of a class is problematic. If the class is extended, the thread can be started before subclass' constructor is executed.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-58082464672889879312012-06-08T19:27:19.759-06:002012-06-08T19:27:19.759-06:00The most recent Concurrency-related bug I ran into...The most recent Concurrency-related bug I ran into was an object that in its constructor created an ExecutorService, but when the object was no longer referenced, it had never shutdown the ExecutorService. Thus, over a period of weeks, thousands of threads leaked, eventually causing the system to crash. (Technically, it didn't crash, but it did stop functioning properly, while continuing to run.)<br /><br />Technically, I suppose this isn't a concurrency problem, but it's a problem relating to use of the java.util.concurrency libraries.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-12890197804831897872012-06-08T19:27:15.340-06:002012-06-08T19:27:15.340-06:00Not exactly a bug but, the worst sin is providing ...Not exactly a bug but, the worst sin is providing a library you intend other people to use, but not stating which classes/methods are thread-safe and which ones must only be called from a single thread etc.<br /><br />More people should make use of the concurrency annotations (e.g. @ThreadSafe, @GuardedBy etc) described in Goetz's book.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-31394699979880003682012-06-08T19:27:09.550-06:002012-06-08T19:27:09.550-06:00Mutable classes in shared data structures
Thread1...Mutable classes in shared data structures<br /><br />Thread1:<br /> Person p = new Person("John");<br /> sharedMap.put("Key", p);<br /> assert(p.getName().equals("John"); // sometimes passes, sometimes fails<br /><br />Thread2:<br /> Person p = sharedMap.get("Key");<br /> p.setName("Alfonso");<br /><br /><br />When this happens, the code is far more complex that this simplified example. Replicating, finding and fixing the bug is hard. Perhaps it could be avoided if we could mark certain classes as immutable and certain data structures as only holding immutable objects.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-7350580141200353952012-06-08T19:27:06.945-06:002012-06-08T19:27:06.945-06:00I believe in the future the main problem with Java...I believe in the future the main problem with Java will be the (lack of) visibility guarantees for constructors. For example, if you create the following class<br /><br />class MyClass {<br /> public int a = 1;<br />}<br /><br /><br />and then just read the value MyClass.a from another thread, MyClass.a could be either 0 or 1, depending on the JavaVM's implementation and mood. Today the chances for 'a' being 1 are very high. But on future NUMA machines this may be different. Many people are not aware of this and believe that they don't need to care about multi-threading during the initialization phase.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-38857157251634602272012-06-08T19:27:03.679-06:002012-06-08T19:27:03.679-06:00Arbitrary method calls should not be made from wit...Arbitrary method calls should not be made from within synchronized blocks.<br /><br />Dave Ray touched on this in his first answer, and in fact I also encountered a deadlock also having to do with invoking methods on listeners from within a synchronized method. I think the more general lesson is that method calls should not be made "into the wild" from within a synchronized block - you have no idea if the call will be long-running, result in deadlock, or whatever.<br /><br />In this case, and usually in general, the solution was to reduce the scope of the synchronized block to just protect a critical private section of code. <br /><br />Also, since we were now accessing the Collection of listeners outside of a synchronized block, we changed it to be a copy-on-write Collection. Or we could have simply made a defensive copy of the Collection. The point being, there are usually alternatives to safely access a Collection of unknown objects.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-16097979714752687842012-06-08T19:26:59.288-06:002012-06-08T19:26:59.288-06:00My biggest problem has always been deadlocks, espe...My biggest problem has always been deadlocks, especially caused by listeners that are fired with a lock held. In these cases, it's really easy to get inverted locking between two threads. In my case, between a simulation running in one thread and a visualization of the simulation running in the UI thread.<br /><br />EDIT: Moved second part to separate answer.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-51211270407004189282012-06-08T19:26:56.834-06:002012-06-08T19:26:56.834-06:00Thinking you are writing single-threaded code, but...Thinking you are writing single-threaded code, but using mutable statics (including singletons). Obviously they will be shared between threads. This happens surprisingly often.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-9747805282826491542012-06-08T19:26:51.900-06:002012-06-08T19:26:51.900-06:00Until I took a class with Brian Goetz I didn't...Until I took a class with Brian Goetz I didn't realize that the non-synchronized getter of a private field mutated through a synchronized setter is never guaranteed to return the updated value. Only when a variable is protected by synchronized block on both reads AND writes will you get the guarantee of the latest value of the variable.<br /><br />public class SomeClass{<br /> private Integer thing = 1;<br /><br /> public synchronized void setThing(Integer thing)<br /> this.thing = thing;<br /> }<br /><br /> /**<br /> * This may return 1 forever and ever no matter what is set<br /> * because the read is not synched<br /> */<br /> public Integer getThing(){<br /> return thing; <br /> }<br />}Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-78299123897954614682012-06-08T19:26:49.063-06:002012-06-08T19:26:49.063-06:00It can be easy to think synchronized collections g...It can be easy to think synchronized collections grant you more protection than they actually do, and forget to hold the lock between calls. If have seen this mistake a few times:<br /><br /> List<String> l = Collections.synchronizedList(new ArrayList<String>());<br /> String[] s = l.toArray(new String[l.size()]);<br /><br /><br />For example, in the second line above, the toArray and size() methods are both thread safe in their own right, but the size() is evaluated separately from the toArray(), and the lock on the List is not held between these two calls. If you run this code with another thread concurrently removing items from the list, sooner or later you will end up with a new String[] returned which is larger than required to hold all the elements in the list, and has null values in the tail. It is easy to think that because the two method calls to the List occur in a single line of code this is somehow an atomic operation, but it is not.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-52128282330590612862012-06-08T19:26:47.063-06:002012-06-08T19:26:47.063-06:00Forgetting to wait() (or Condition.await()) in a l...Forgetting to wait() (or Condition.await()) in a loop, checking that the waiting condition is actually true. Without this, you run into bugs from spurious wait() wakeups. Canonical usage should be:<br /><br /> synchronized (obj) {<br /> while (<condition does not hold>) {<br /> obj.wait();<br /> }<br /> // do stuff based on condition being true<br /> }Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-68920505546933967482012-06-08T19:26:42.469-06:002012-06-08T19:26:42.469-06:00Another common bug is poor exception handling. Whe...Another common bug is poor exception handling. When a background thread throws an exception, if you don't handle it properly, you might not see the stack trace at all. Or perhaps your background task stops running and never starts again because you failed to handle the exception.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-41669285714790116322012-06-08T19:26:38.938-06:002012-06-08T19:26:38.938-06:00The most common bug we see where I work is program...The most common bug we see where I work is programmers perform long operations, like server calls, on the EDT, locking up the GUI for a few seconds and making the app unresponsive.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-22678049393168838012012-06-08T19:26:32.512-06:002012-06-08T19:26:32.512-06:00Not properly synchronizing on objects returned by ...Not properly synchronizing on objects returned by Collections.synchronizedXXX(), especially during iteration or multiple operations:<br /><br />Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());<br /><br />...<br /><br />if(!map.containsKey("foo"))<br /> map.put("foo", "bar");<br /><br /><br />That's wrong. It should be:<br /><br />synchronized(map) {<br /> if(!map.containsKey("foo"))<br /> map.put("foo", "bar");<br />}<br /><br /><br />Or with a ConcurrentMap implementation:<br /><br />map.putIfAbsent("foo", "bar");Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-79501820532636264792012-06-08T19:26:31.129-06:002012-06-08T19:26:31.129-06:00Though probably not exactly what you are asking fo...Though probably not exactly what you are asking for, the most frequent concurrency-related problem I've encountered (probably because it comes up in normal single-threaded code) is a<br /><br />java.util.ConcurrentModificationException<br /><br />caused by things like:<br /><br />List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));<br />for (String string : list) { list.remove(string); }Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-33048408804389490712012-06-08T19:26:26.054-06:002012-06-08T19:26:26.054-06:00Double-Checked Locking. By and large.
The paradig...Double-Checked Locking. By and large.<br /><br />The paradigm, which I started learning the problems of when I was working at BEA, is that people will check a singleton in the following way:<br /><br />public Class MySingleton {<br /> private static MySingleton s_instance;<br /> public static MySingleton getInstance() {<br /> if(s_instance == null) {<br /> synchronized(MySingleton.class) { s_instance = new MySingleton(); }<br /> }<br /> return s_instance;<br /> }<br />}<br /><br /><br />This never works, because another thread might have gotten into the synchronized block and s_instance is no longer null. So the natural change is then to make it:<br /><br /> public static MySingleton getInstance() {<br /> if(s_instance == null) {<br /> synchronized(MySingleton.class) {<br /> if(s_instance == null) s_instance = new MySingleton();<br /> }<br /> }<br /> return s_instance;<br /> }<br /><br /><br />That doesn't work either, because the Java Memory Model doesn't support it. You need to declare s_instance as volatile to make it work, and even then it only works on Java 5.<br /><br />People that aren't familiar with the intricacies of the Java Memory Model mess this up all the time.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-18090592644666821732012-06-08T19:26:21.839-06:002012-06-08T19:26:21.839-06:00A common problem is using classes like Calendar an...A common problem is using classes like Calendar and SimpleDateFormat from multiple threads (often by caching them in a static variable) without synchronization. These classes are not thread-safe so multi-threaded access will ultimately cause strange problems with inconsistent state.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.comtag:blogger.com,1999:blog-865923359735383241.post-3345063866912829102012-06-08T19:26:19.543-06:002012-06-08T19:26:19.543-06:00One classic problem is changing the object you'...One classic problem is changing the object you're synchronizing on while synchronizing on it:<br /><br />synchronized(foo) {<br /> foo = ...<br />}<br /><br /><br />Other concurrent threads are then synchronizing on a different object and this block does not provide the mutual exclusion you expect.Userhttps://www.blogger.com/profile/11557173689529910046noreply@blogger.com