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
You might consider using a concurrent implementation of List, instead of ArrayList. Perhaps a CopyOnWriteArrayList.
final List<Integer> list = new CopyOnWriteArrayList<Integer>();
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 ...);
}
}
}
...
}
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.
Related
It is pretty unsafe to iterate over a List, which is being performed add / remove operation by another thread.
That's why we need need CopyOnWriteArrayList
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
// java.util.ConcurrentModificationException
for (String s : list) {
System.out.println(s);
}
}
}
});
thread.start();
for (int i=0; i<1000; i++) {
list.add("string" + i);
}
Thread.sleep(Long.MAX_VALUE);
}
However, how about set operation. Currently, the following code doesn't throw any exception.
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
list.add("dummy");
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
for (String s : list) {
System.out.println(s);
}
}
}
});
thread.start();
for (int i=0; i<1000; i++) {
list.set(0, "smart");
}
Thread.sleep(Long.MAX_VALUE);
}
Even though there isn't any unexpected outcome, I was wondering, if the thread only performing set operation on the List, is it a good practice that we don't using any locking mechanism, or copy n write mechanism?
Quoting the javadoc of ArrayList:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.)
So no, it does not need to be synchronized.
Just for practice I wanted to implement the java synchronized keyword as a java object.
Would you say the code below is a good design for this?
I guess AtomicReference would have a similar performance to AtomicBoolean?
Updated code after suggestions:
public class SynchronizedBlock implements Runnable{
private final Lock lock;
private final Runnable runnable;
public SynchronizedBlock(Runnable r, Lock l){
runnable = r;
lock = l;
}
public void run() {
try {
while(!lock.compareAndSet(false, true)){
Thread.sleep(100);
}
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Lock {
private final AtomicReference<Boolean> locked = new AtomicReference<Boolean>(false);
public boolean compareAndSet(boolean expected, boolean update){
return locked.compareAndSet(expected, update);
}
public boolean isLocked(){
return locked.get();
}
public void unlock(){
locked.set(false);
}
}
#Test
public void test() {
final SynchronizedBlock sb = new SynchronizedBlock(new Runnable(){
public void run() {
x++;
System.out.println(x);
}
}, new Lock());
Runnable r1 = new Runnable(){
int c = 0;
public void run() {
while(c<10){
sb.run();
c++;
}
}
};
Runnable r2 = new Runnable(){
int c = 0;
public void run() {
while(c<10){
sb.run();
c++;
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
while (t1.isAlive() && t2.isAlive()){
}
assertEquals(20,x);
}
You should add a method to encapsulate the compareAndSwap, and there is no point looping for the lock to be free before attempting to obtain it. Why get in the situation where you can see the lock is free but by the time you try to take it, it is gone.
I would remove the lock method and place the unlock in a finally lock so that an Exception/Error doesn't result in a lock which never unlocks.
Also I would use an AtomicBoolean which is more natural than an AtomicReference
Firstly and most importantly, you should remove Thread.sleep(100). This will cause at least 100ms latency even in only 2-thread contention.
You can simply use AtomicBoolean instead of AtomicReference to simplify your code. Also if you're really concerned about concurrency in high-contention situation, you can modify your code to check if it's locked before doing CAS.
while (true) {
if (lock.isLocked()) continue; // or get() == true if you use AtomicBoolean
if (lock.compareAndSet(false, true))
break;
}
This is an example of TTAS(Test-Test-And-Set) locking which takes advantage of local-spinning to reduce main-memory access while looping.
See http://en.wikipedia.org/wiki/Test_and_Test-and-set
I need to iterate an ArrayList of String in a different thread, I don't need to add or delete items, just to iterate.
How can I do it?
Weill in its most basic form you do something like this. But it seems like there's a lot more to your question than you asked us?
final List<Item> items = new ArrayList<Item>();
items.addAll(stuff);
new Thread(new Runnable() {
public void run() {
for (Item item: items) {
System.out.println(item);
}
}
}).start();
The only issue you may encounter with this, that the reading thread accesses the same data as the publisher thread. For that you need to pass the reference to the other thread in thread-safely manner (i.e. via a field declared with volatile modifier, using AtomicReference or pass the memory barrier in reader and writer threads by any other way, like passing a ReentrantLock or synchronize block). Note - that you do not need to iterate it inside a synchronization. Just pass the memory barrier before reading the list.
For example (ReentrantLock):
private final ReadWriteLock lock = new ReentrantReadWriteLock();
final Lock w = lock.writeLock();
w.lock();
try {
// modifications of the list
} finally {
w.unlock();
}
.................................
final Lock r = lock.readLock();
r.lock();
try {
// read-only operations on the list
// e.g. copy it to an array
} finally {
r.unlock();
}
// and iterate outside the lock
Thread splashThread = new Thread() {
#Override
public void run() {
List<String> mylist = new ArrayList<String>();
mylist.add("I");
mylist.add("Am");
mylist.add("definitely");
mylist.add("becoming");
mylist.add("a");
mylist.add("better");
mylist.add("programmer");
Iterator<?> i1 = mylist.iterator();
while (i1.hasNext()) {
System.out.println(i1.next());
}
}
};
splashThread.start();
}
I have searched a lot but not able to find particular solution. There are also some question regarding this on stackoverflow but i am not able to find satisfactory answer so i am asking it again.
I have a class as follow in java . I know how to use threads in java.
//please do not consider syntax if there is printing mistake, as i am typing code just for showing the concept in my mind
public class myclass{
private List<String> mylist=new ArrayList<String>();
public addString(String str){
//code to add string in list
}
public deleteString(String str){//or passing an index to delete
//code to delete string in list
}
}
now i want to do these two operations simultaneously. for that i have created two thread class one performs addString() logic in run and another perform deleteString() logic.i am passing mylist in the constructor of each thread but how can i return an object after performing addition and deletion to mylist?
Before i was thinking that "If i am passing the mylist in constructor of thread it passes the address of the mylist to thread and thread performs operations on it that changes refer to mylist object" But it is not like that as the changes are not reflacted to mylist object . can any one elaborate this?
what is the best way to achieve this?
the requirement is like that if a thread is inserting an element at last another thread should be able to delete some element at other index say 2nd simultaneously.
EDIT
i have done it as follow: thanx to Enno Shioji
public class myClass {
private List<String> mylist = Collections.synchronizedList(new ArrayList<String>());
public myClass(){
mylist.add("abc");
mylist.add("def");
mylist.add("ghi");
mylist.add("jkl");
}
public void addString(String str) {
mylist.add(str);
}
public void displayValues() {
for (int i = 0; i < mylist.size(); i++) {
System.out.println("value is " + mylist.get(i) + "at " + i);
}
}
public void deleteString(int i) {
mylist.remove(i);
}
}
class addThread {
public static void main(String a[]) {
final myClass mine = new myClass();
Thread t1 = new Thread() {
#Override
public void run() {
mine.displayValues();
mine.addString("aaa");
mine.displayValues();
}
};
Thread t2 = new Thread() {
public void run() {
mine.displayValues();
mine.deleteString(1);
mine.displayValues();
}
};
t1.start();
t2.start();
}
}
is there any other way to do so?
Use Synchronized List , It would be thread safe
Use Collection.synchronizedList(yourPlainList)
Threads and object instance are different concepts. If you want to share data among threads, you need to access a single object instance from two threads. In this case, you should do something like this.
public class MyClass{
private final List<String> mylist = new ArrayList<String>();
public synchronized void addString(String str){
//code to add string in list
}
public synchronized void deleteString(String str){
//or passing an index to delete
//code to delete string in list
}
}
and then
final MyClass mine = new MyClass();
Thread t1 = new Thread(){
public void run(){
mine.addString("aaa");
}
}();
Thread t2 = new Thread(){
public void run(){
mine.deleteString("bbb");
}
}();
t1.start();
t2.start();
Note how you are referring to the same object instance (mine) from both threads. Also note that I added the synchronized keyword to make MyClass thread-safe. This forces all operations to be done sequentially rather than truly "simultaneously". If you want true simultaneous operations on the collection, you will need to use concurrent data structures like a Skip List and get rid of synchronized keyword.
I have a collection which guaranteed to be visible across threads. However that doesn't guarantee visibility of states of items which are stored in this collection(eg. if I have collection of StringBuilder(mutable, not thread safe) then I have to synchronize on each item in collection during write/read, right?). So, what happens when I have collection of objects which are used for guaranteeing happen-before by themselves(eg. countdownlatch). Do I need to synchronize on each item somehow when calling await/countDown? Code below roughly illustrate this dilemma:
public class SyncQuestion {
final List<CountDownLatch> lathces = new ArrayList<CountDownLatch>();
SyncQuestion() {
lathces.add(new CountDownLatch(1));
}
public static void main(String[] args) throws InterruptedException {
final SyncQuestion sync = new SyncQuestion();
final Thread sleepingThread = new Thread() {
public void run() {
for (CountDownLatch latch : sync.lathces) {
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
};
final Thread wakingThread = new Thread() {
public void run() {
for (CountDownLatch latch : sync.lathces) {
latch.countDown();
}
};
};
sleepingThread.start();
wakingThread.start();
sleepingThread.join();
wakingThread.join();
}
}
Please correct me in my assumptions, if they are wrong.
A CountDownLatch is basically a wrapper on AbstractQueuedSynchronizer whose state is a volatile int that is mutated via Unsafe.compareAndSwapInt (which is an atomic operation).
Therefore in this specific case, as Cameron Skinner said, there is no need to synchronize because it enforces that happens-before for you.
I don't believe you need to manually synchronize in this case because the latches are internally thread-safe.