The following code triggers a ConcurrentModificationException very, very quickly:
import java.util.*;
public class SynchFail {
static List<Integer> LIST = new ArrayList<Integer>();
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
LIST.add(1);
}
}}).start();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
List<Integer> syncList = Collections.synchronizedList(LIST);
synchronized(syncList) {
for (Integer thisInt : syncList) {
}
}
}
}}).start();
}
}
... whereas the following behaves as it should:
import java.util.*;
public class SynchSucceed {
static List<Integer> LIST = new ArrayList<Integer>();
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized(LIST) {
LIST.add(1);
}
}
}}).start();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized(LIST) {
for (Integer thisInt : LIST) {
}
}
}
}}).start();
}
}
... my understanding was that synchronized collections were to prevent ConcurrentModificationExceptions in situations like this (but clearly they do not).
Given this: where should I make use of these ?
In the first code snippet, you have not followed the instructions in the documentation of synchronizedList:
In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list.
In the other thread, you are adding to the list via the original LIST, not the "returned list". LIST is just a normal ArrayList and calling add on it won't acquire any locks or anything like that, so add could still be successfully called while the iteration is in progress.
If you did:
final static List<Integer> LIST = Collections.synchronizedList(new ArrayList<>());
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
LIST.add(1);
}
}}).start();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized(LIST) {
for (Integer thisInt : LIST) {
}
}
}
}}).start();
}
Then it wouldn't throw a CME. When you call add on a synchronised list, it tries to acquire the intrinsic lock on LIST. If iteration is in progress, the lock would have been already held by the other thread (since you did synchronized (LIST) { ... } there), so it will wait until the iteration is over. Compare this with the second code snippet, and notice how this saves you from writing an extra synchronized (LIST) {} block around the add call.
Couple of things:
If you need sychronized access to an ArrayList you should use Vector instead. It does the same thing but its methods are syncrhonized.
in your case, the 2nd snippet works because you are syncing over the same object LIST in both threads
Related
can someone show example why it is impoertent to use only synchronized map (meaing hashtable or ConcurrentMap) in a multithreaded application ?
I understand why it is impoertent to synchronized the application methods that doing actions on the map , but why the map itself need to be synchronized ?
I tried this :
public class MapTest {
private static final TreeMap<String, String> map = new TreeMap<>();
public static void main(String[] args) {
Thread t = new Thread() {
public synchronized void run() {
map.put("pp", "ww");
}
};
Thread r = new Thread() {
public synchronized void run() {
System.out.println("s:" + map.get("pp"));
}
};
t.start();
r.start();
}
}
but I'm always getting same "good" result : s:ww allthoght the map is not synchronized
I have method like this:
public void rentBook(ArrayList<book> list, Book book)
{
if(!list.isEmpty())
{
list.remove(book);
book.setAvailable(false);
Biblioteka.listOfRented.add(book);
}
else
System.out.println("No any books left");
}
and I want to invoke this method in run() method of Thread. I'm making library system and I want to make the reade ( thread) can rent book (method rentBook ) I have no idea how can I correctly pass parameters. Any tips :/?
As discussed in the comments, here's two (compiling, running) ways you can do it:
public void methodUsingFinals() {
final ArrayList<book> list = new ArrayList<>();
final Book currentBook = new Book();
new Thread(new Runnable() {
#Override
public void run() {
rentBook(list, currentBook);
}
});
}
public void methodAcceptingValues(ArrayList<book> list, Book currentBook) {
new Thread(new Runnable() {
#Override
public void run() {
rentBook(list, currentBook);
}
});
}
suppose we have these classes and read the comments
class Work {
void doWork(){ }
void commit(){}
}
class MyRunable implements Runnable {
run(){
Work work=new Work();
work.doWork();
//i can't write work.commit() here, because sometimes i want Thread runs both methods
//and sometimes runs only doWork()
}
}
class Tasks{
main(){
MyRunable myRunable=new MyRunable();
Thread t=new Thread(myRunable);
t.start();
//suppose now i need to call commit() method by the same thread (t)
//how can i do that
}
}
also i don't want to use constructor to determine if i want to call both method or not
You could try using a thread pool with a single thread and keep enqueuing methods as needed:
class Tasks {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Work work = new Work();
exec.submit(new Runnable() {
public void run() {
work.doWork();
}
});
// later
exec.submit(new Runnable() {
public void run() {
work.commit();
}
});
}
}
This way, both methods will be executed in a sequence by the same thread, but separately.
Add parameter to your class MyRunnable. Call this parameter "runingMode". It could be an enum:
enum RunningMode {
DO_WORK {
public void work(Work work) {
work.doWork();
}
},
COMMIT {
public void work(Work work) {
work.commit();
}
};
public abstract void work();
}
Now your class MyRunnable should have list of modes:
class MyRunable implements Runnable {
private Collection<RunningMode> modes;
MyRunable(Collection<RunningMode> modes) {
this.modes = modes;
}
}
Implement run() method as following:
Work work=new Work();
for (RunningMode mode : modes) {
mode.work(work);
}
work.doWork();
Create instance of your class passing to it the mode you currently need:
MyRunable myRunable=new MyRunable(Arrays.asList(RunningMode.DO_WORK, RunningMode.COMMIT));
You could use an anonymous class.
final boolean condition = ...
Thread t = new Thread(new Runnable() {
public void run() {
Work work=new Work();
work.doWork();
if(condition)
work.commit();
}});
t.start();
I have following code for a chat server application in Java -
public synchronized List<ChatMessage> getMessages(int messageNumber) {
return messages.subList(messageNumber + 1, messages.size());
}
public synchronized int addMessage(ChatMessage c) {
messages.add(c);
return messages.size()-1;
}
I have following test code -
public static void main(String[] args) {
final ChatRoom c = new ChatRoom();
Thread user1 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0);
}
}
});
Thread user2 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0).size();
}
}
});
user1.start();
user2.start();
}
I am getting a ConcurrentModificationException.
How is this possible?
How is this possible?
Your getMessages method just returns a view on the original list. It doesn't create a copy of the list. So one thread is using a view on the list while another modifies the list - at that point, you get the exception.
From the docs for List.subList:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
It's not clear what you're really trying to achieve here, but fundamentally you can't use subList to magically create a thread-safe list :)
The simplest thing to do is to create a combined method
public synchronized int addMessageAndGetCount(ChatMessage c) {
messages.add(c);
return messages.size();
}
public static void main(String... args) {
final ChatRoom c = new ChatRoom();
final Runnable runner = new Runnable() {
public void run() {
for(int i = 0; i < 1000; i++) {
c.addMessageAndGetCount(new ChatMessage());
}
}
};
new Thread(runner).start();
new Thread(runner).start();
}
You cannot safely return a list or a subList from a synchronized block. You can return a copy but all you need is the size.
Is there a way to access an anonymous outer class? A normal class can be accessed by ClassName.this. This doesn't work, as an anonymous class obviously doesn't have a name. I also tried using the extended class/interface (like Runnable.this) but it doesn't seem like it would work this way.
I'm sure this may be not the best coding style, I'm just curious if it's possible without storing this of the outer in a variable.
Example, watch out for outer.this:
public class A
{
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (outher.this) {
outher.this.notify();
}
}
}).start();
try {
synchronized (this) {
wait();
}
} catch (final InterruptedException ex) {}
}
}).start();
}
}
No, there is no way to access anonymous classes from anywhere, except from inside them (i.e. otherwise than by this reference). Or by an explicitly declared variable.
final Runnable r1 = new Runnable() {...};
Runnable r2 = new Runnable() {
public void run() {
synchronized(r1) {...}
}
};
You could add a method to return this middle this. It would be in scope but not hidden (is that the right term? Shadowed? I forget.).
public static void main(String[] args) {
new Thread(new Runnable() {
Runnable middleThis() { return this; } // <-- this
#Override
public void run() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (middleThis()) {
middleThis().notify();
Note, although anonymous inner classes have no name, they still are types. So adding members is visible to the immediate expression (new X() { Y z; }.z) and inside. You can't do middleThis().middleThis().