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();
}
Related
I have a class in which I have a ConcurrentHashMap which is updated by a single thread every 30 seconds and then I have multiple reader threads reading from the same ConcurrentHashMap by calling getNextSocket() method.
Below is my singleton class which on the initialization calls connectToSockets() method to populate my ConcurrentHashMap and then starts a background thread which updates the same map every 30 second by calling updateSockets() method.
And then from multiple threads I am calling getNextSocket() method to get next available live socket which uses same map to get the information out. I also have SocketInfo class which is immutable which contains the state of all the sockets whether they are live or not.
public class SocketHolder {
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final Map<DatacenterEnum, List<SocketInfo>> liveSocketsByDc = new ConcurrentHashMap<>();
// Lazy Loaded Singleton Pattern
private static class Holder {
private static final SocketHolder INSTANCE = new SocketHolder();
}
public static SocketHolder getInstance() {
return Holder.INSTANCE;
}
private SocketHolder() {
connectToSockets();
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
updateSockets();
}
}, 30, 30, TimeUnit.SECONDS);
}
private void connectToSockets() {
Map<DatacenterEnum, ImmutableList<String>> socketsByDc = TestUtils.SERVERS;
for (Map.Entry<DatacenterEnum, ImmutableList<String>> entry : socketsByDc.entrySet()) {
List<SocketInfo> addedColoSockets = connect(entry.getKey(), entry.getValue(), ZMQ.PUSH);
liveSocketsByDc.put(entry.getKey(), addedColoSockets);
}
}
private List<SocketInfo> connect(DatacenterEnum dc, List<String> addresses, int socketType) {
List<SocketInfo> socketList = new ArrayList<>();
// ... some code here
return socketList;
}
// called from multiple reader threads to get next live available socket
public Optional<SocketInfo> getNextSocket() {
Optional<SocketInfo> liveSocket = getLiveSocket(liveSocketsByDc.get(DatacenterEnum.CORP));
return liveSocket;
}
private Optional<SocketInfo> getLiveSocket(final List<SocketInfo> listOfEndPoints) {
if (!CollectionUtils.isEmpty(listOfEndPoints)) {
Collections.shuffle(listOfEndPoints);
for (SocketInfo obj : listOfEndPoints) {
if (obj.isLive()) {
return Optional.of(obj);
}
}
}
return Optional.absent();
}
// update CHM map every 30 seconds
private void updateSockets() {
Map<DatacenterEnum, ImmutableList<String>> socketsByDc = TestUtils.SERVERS;
for (Entry<DatacenterEnum, ImmutableList<String>> entry : socketsByDc.entrySet()) {
List<SocketInfo> liveSockets = liveSocketsByDc.get(entry.getKey());
List<SocketInfo> liveUpdatedSockets = new ArrayList<>();
for (SocketInfo liveSocket : liveSockets) {
Socket socket = liveSocket.getSocket();
String endpoint = liveSocket.getEndpoint();
boolean sent = ....;
boolean isLive = sent ? true : false;
// is this right here? or will it cause any race condition?
SocketInfo state = new SocketInfo(socket, liveSocket.getContext(), endpoint, isLive);
liveUpdatedSockets.add(state);
}
// update map with new liveUpdatedSockets
liveSocketsByDc.put(entry.getKey(), liveUpdatedSockets);
}
}
}
Question:
Is my above code thread safe and there is no race condition in updateSockets() and getNextSocket() method?
In my updateSockets() method, I extract List<SocketInfo> from liveSocketsByDc ConcurrentHashMap which was already populated before in connectToSockets() method during initialization or next interval of 30 second in updateSockets() method and then I am iterating same list liveSockets and create a new SocketInfo object depending on whether isLive is true or false. And then I update liveSocketsByDc ConcurrentHashMap with this new SocketInfo object. Does this look right? Because from multiple reader threads I am going to call getNextSocket() method which inturn calls getLiveSocket method which uses same map to get the next available live socket.
I am iterating liveSockets list and then creating a new SocketInfo object by just changing isLive field and other things will stay same. Is this right?
If there is a thread safety issue, what is the best way to fix this?
Here:
List<SocketInfo> liveSockets = liveSocketsByDc.get(entry.getKey());
Your different threads are potentially writing/reading the same list object in parallel.
So: not thread safe. It doesn't help to have an "outer" thread-safe data structure; when that thread-safe thing contains data ... that is not thread-safe; but then "worked on" in parallel!
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.
Let's say I have two lists: fooList, and barList. Also, let's say I have two threads: first one iterates over fooList and if certain criteria is met (condition is true) it removes element from fooList and adds it to barList. Second one iterates over barList, and if some other condition is true it removes element from barList, and adds it to fooList.
The way I handled it is:
private static Object sharedLock = new Object();
Thread t1 = new Thread() {
public void run() {
synchronized (sharedLock) {
for (Iterator<String> iterator = fooList.iterator(); iterator.hasNext();) {
String fooElement = iterator.next();
if (condition == true) {
iterator.remove();
barList.add(fooElement);
}
}
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized (sharedLock) {
for (Iterator<String> iterator = barList.iterator(); iterator.hasNext();) {
String barElement = iterator.next();
if (otherCondition == true) {
iterator.remove();
fooList.add(barElement);
}
}
}
}
};
What I want to know is have I handled it properly? Is there a race condition possibility? Is there a better way to achieve the same functionality?
EDIT Looks like proper way of implementing this is:
Thread t1 = new Thread() {
public void run() {
for (String fooElement : fooList) {
if (condition == true) {
fooList.remove(fooElement);
barList.add(fooElement);
}
}
}
};
Thread t2 = new Thread() {
public void run() {
for (String barElement : barList) {
if (otherCondition == true) {
barList.remove(barElement);
fooList.add(barElement);
}
}
}
};
where both: fooList and barList are of type CopyOnWriteArrayList<String>
Don't reinvent the wheel: use a threadsafe implementation of List from the JDK:
List<String> fooList = new CopyOnWriteArrayList<>();
See javadoc
The way you implemented it now, t1 and t2 will run sequentially and not parallel. Whichever one starts first, claims the lock, performs his entire loop, terminates and releases the lock for the other.
The good thing is: there is no race condition. The bad thing is: there is no parallelism.
In general, it's a bad idea to work directly with locks if you can avoid it. Java contains a load of collections specifically for concurrent use. See Java Concurrency Utils
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.
In my application I'm performing somewhat heavy lookup operations. These operations must be done within a single thread (persistence framework limitation).
I want to cache the results. Thus, I have a class UMRCache, with an inner class Worker:
public class UMRCache {
private Worker worker;
private List<String> requests = Collections.synchronizedList<new ArrayList<String>>());
private Map<String, Object> cache = Collections.synchronizedMap(new HashMap<String, Object>());
public UMRCache(Repository repository) {
this.worker = new Worker(repository);
this.worker.start();
}
public Object get(String key) {
if (this.cache.containsKey(key)) {
// If the element is already cached, get value from cache
return this.cache.get(key);
}
synchronized (this.requests) {
// Add request to queue
this.requests.add(key);
// Notify the Worker thread that there's work to do
this.requests.notifyAll();
}
synchronized (this.cache) {
// Wait until Worker has updated the cache
this.cache.wait();
// Now, cache should contain a value for key
return this.cache.get(key);
}
}
private class Worker extends Thread {
public void run() {
boolean doRun = true;
while (doRun) {
synchronized (requests) {
while (requests.isEmpty() && doRun) {
requests.wait(); // Wait until there's work to do
}
synchronized (cache) {
Set<String> processed = new HashSet<String>();
for (String key : requests) {
// Do the lookup
Object result = respository.lookup(key);
// Save to cache
cache.put(key, result);
processed.add(key);
}
// Remove processed requests from queue
requests.removeAll(processed);
// Notify all threads waiting for their requests to be served
cache.notifyAll();
}
}
}
}
}
}
I have a testcase for this:
public class UMRCacheTest extends TestCase {
private UMRCache umrCache;
public void setUp() throws Exception {
super.setUp();
umrCache = new UMRCache(repository);
}
public void testGet() throws Exception {
for (int i = 0; i < 10000; i++) {
final List fetched = Collections.synchronizedList(new ArrayList());
final String[] keys = new String[]{"key1", "key2"};
final String[] expected = new String[]{"result1", "result2"}
final Random random = new Random();
Runnable run1 = new Runnable() {
public void run() {
for (int i = 0; i < keys.length; i++) {
final String key = keys[i];
final Object result = umrCache.get(key);
assertEquals(key, results[i]);
fetched.add(um);
try {
Thread.sleep(random.nextInt(3));
} catch (InterruptedException ignore) {
}
}
}
};
Runnable run2 = new Runnable() {
public void run() {
for (int i = keys.length - 1; i >= 0; i--) {
final String key = keys[i];
final String result = umrCache.get(key);
assertEquals(key, results[i]);
fetched.add(um);
try {
Thread.sleep(random.nextInt(3));
} catch (InterruptedException ignore) {
}
}
}
};
final Thread thread1 = new Thread(run1);
thread1.start();
final Thread thread2 = new Thread(run2);
thread2.start();
final Thread thread3 = new Thread(run1);
thread3.start();
thread1.join();
thread2.join();
thread3.join();
umrCache.dispose();
assertEquals(6, fetched.size());
}
}
}
The test fails randomly, at about 1 out of 10 runs. It will fail at the last assertion: assertEquals(6, fetched.size()), at assertEquals(key, results[i]), or sometimes the test runner will never finish.
So there's something buggy about my thread logic. Any tips?
EDIT:
I might have cracked it now, thanks to all who have helped.
The solution seems to be:
public Object get(String key) {
if (this.cache.containsKey(key)) {
// If the element is already cached, get value from cache
return this.cache.get(key);
}
synchronized (this.requests) {
// Add request to queue
this.requests.add(key);
// Notify the Worker thread that there's work to do
this.requests.notifyAll();
}
synchronized (this.cache) {
// Wait until Worker has updated the cache
while (!this.cache.containsKey(key)) {
this.cache.wait();
}
// Now, cache should contain a value for key
return this.cache.get(key);
}
}
get() method logic can miss result and get stuck
synchronized (this.requests) {
// Add request to queue
this.requests.add(key);
// Notify the Worker thread that there's work to do
this.requests.notifyAll();
}
// ----- MOMENT1. If at this moment Worker puts result into cache it
// will be missed since notification will be lost
synchronized (this.cache) {
// Wait until Worker has updated the cache
this.cache.wait();
// ----- MOMENT2. May be too late, since cache notifiation happened before at MOMENT1
// Now, cache should contain a value for key
return this.cache.get(key);
}
The variable fetched in your test is an ArrayList and is accessed and updated from your two anonymous Runnable instances.
ArrayList is not thread safe, from the documentation:
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.) This is
typically accomplished by
synchronizing on some object that
naturally encapsulates the list. If no
such object exists, the list should be
"wrapped" using the
Collections.synchronizedList method.
This is best done at creation time, to
prevent accidental unsynchronized
access to the list:
Hence I think your test needs a little adjusting.
I noticed your lookup in cache isn't atomic operation:
if (this.cache.containsKey(key)) {
// If the element is already cached, get value from cache
return this.cache.get(key);
}
Since you never delete from cache in your code, you always will get some value by this code. But if, in future, you plan to clean cache, lack of atomicity here will become a problem.