wutzebaer
wutzebaer

Reputation: 14865

Lock objects for all threads?

I have this small sample of code, while modifying the list, i lock it with synchronized, but while reading the list it comes to ConcurrentModificationException, because without "synchronized" the lock has no effect. Is it possible to lock an object for all threads which use the object, even the un-synchronized, too?

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {

    public static void main(String[] args) {

        final Random r = new Random(System.currentTimeMillis());

        List<Integer> list = new ArrayList<>();

        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    synchronized (list) {
                        list.add(r.nextInt());
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    for (Integer i : list) {
                        System.out.println(i);
                    }
                }
            }
        }).start();
    }
}

the backgorund is that i dont want to change all pieces in my code which read the object

Upvotes: 0

Views: 426

Answers (3)

Solomon Slow
Solomon Slow

Reputation: 27115

Is it possible to lock an object for all threads which use the object.

In a word, No. When one thread enters a synchronized(foo) {...} block, that does not prevent other threads from accessing or modifying foo. The only thing it prevents is, it prevents other threads from synchronizing on the same object at the same time.

What you can do, is you can create your own class that encapsulates both the lock and the data that the lock protects.

class MyLockedList {
    private final Object lock = new Object();
    private final List<Integer> theList = new ArrayList<>();

    void add(int i) {
        synchronized(lock) {
            theList.add(i);
        }
    }

    void printAll() {
        synchronized(lock) {
            for (Integer i : theList) {
                System.out.println(... i ...);
            }
        }
    }

    ...
}

Upvotes: 1

David Haim
David Haim

Reputation: 26486

If you can modify the function which concurrently uses the object, just add synchronized in every critical section:

      while (true) {
          synchronized(list){
                for (Integer i : list) {
                      System.out.println(i);
             }
        }
}

if you can't , create a specified lock that is responsible for locking the threads:

Lock lock = new Lock();
new Thread(new Runnable(){
  //...
     synchronized(lock){
       do unsynchonized function on list
     }
  //...
}).start();

new Thread(new Runnable(){
  //...
     synchronized(lock){
       do unsynchonized function on list
     }
  //...
}).start();

the latter may slow down the process if one of the functions already doing some locking, but in this way you can ensure you always synchronize the access to concurrent objects.

Upvotes: 0

David Maust
David Maust

Reputation: 8270

You might consider using a concurrent implementation of List, instead of ArrayList. Perhaps a CopyOnWriteArrayList.

final List<Integer> list = new CopyOnWriteArrayList<Integer>();

Upvotes: 2

Related Questions