Sharing an effectively immutable object between multiple threads - java

Will the updated values in the hashmap below will reflect in the reader threads(the threads will not modifiy the state of the hashMap)?
What if ConcurrentHashMap is used instead?
public class SharedDataTest {
private static class SomeWork implements Runnable {
private Map<String, String> dataTable;
public SomeWork(Map<String, String> dataTable) {
this.dataTable = dataTable;
}
#Override
public void run() {
//do some stuff with dataTable
}
}
public static void main(String[] args) {
Map<String, String> dataTable = new HashMap<String, String>();
dataTable.put("someKey","someValue");
Runnable work1 = new SomeWork(dataTable);
Runnable work2 = new SomeWork(dataTable);
new Thread(work1).start();
new Thread(work2).start();
}
}

If all initialization of the map is done before starting the threads, then there is no need for additional synchronization. The start of a thread will act as a memory barrier, and anything happened before that thread start will be visible to that thread.
Note that if you change the map after threads start, then there is no guarantee on whether or if the threads will see that change.

Yes it will reflect but there may be inconsistency depending on you you do on your run() method because you are not synchronizing externally. Use Collections.synchronizedMap(map) or better use a ConcurrentHashMap which will provide you thread safety for free
public SomeWork(Map<String, String> dataTable) {
this.dataTable = Collections.synchronizedMap(dataTable);
}
Check the documentation of HashMap which asks to synchronize externally in case of concurrency
Note that this implementation is not
synchronized. * If multiple threads access a hash map
concurrently, and at least one of * the threads modifies the map
structurally, it must be * synchronized externally. (A
structural modification is any operation * that adds or deletes one
or more mappings; merely changing the value * associated with a key
that an instance already contains is not a * structural
modification.) This is typically accomplished by * synchronizing on
some object that naturally encapsulates the map.

It will be better to use a ConcurrentHashMap rather than externally synchronize the map.
public class SharedDataTest {
private static class SomeWork implements Runnable {
private Map<String, String> dataTable;
public SomeWork(Map<String, String> dataTable) {
this.dataTable = dataTable;
}
#Override
public void run() {
//do some stuff with dataTable
}
}
public static void main(String[] args) {
Map<String, String> dataTable = new ConcurrentHashMap<String, String>();
dataTable.put("someKey","someValue");
Runnable work1 = new SomeWork(dataTable);
Runnable work2 = new SomeWork(dataTable);
new Thread(work1).start();
new Thread(work2).start();
}
}

Related

thread safety AbstractRoutingDataSource with spring-boot

how to use Multiple database connection on multiple threads..
I know how to use database connection with routingdataSource dynamically
but I think it is not thread safety Because the class is static.!!!
// first thread
ContextHolder.set("firstId");
mapper.select();
ContextHolder.clear(idFirst);
// second thread
ContextHolder.set("secondId");
mapper.select();
ContextHolder.clear(idFirst);
public class ContextHolder {
private static ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void set(String dbType) {
CONTEXT.set(dbType);
}
public static String getClientDatabase() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
like this code.
public class Poller implements Runnable {
#Override
public List<Map<String, Object>> getNext() {
Map<String, Object> params = new HashMap<>();
ContextHolder.set(dbConnectionId);
List<Map<String, Object>> list = blogMapper.findAll(params)
ContextHolder.clear();
return list;
}
....
}
the
private static ThreadLocal<String> CONTEXT = new ThreadLocal<>();
create a threadlocal variable. It means that what you put inside is bound to a specific thread and when you get something it is what in this thread that is returned.
For instance, in thread 1 you set:
CONTEXT.set(1);
in thread 2 you set:
CONTEXT.set(2);
and later thread print what inside with a
CONTEXT.get();
it will print 1 for thread 1 and 2 for thread 2.
So now, if you use a standard synchronous model, it is fine as long as you don't forget to clean the value when you enter and/or exit the request.
As soon as you use async (reactive, executor, ...) it will fail as part of your process will be run on another thread.

Observer pattern and data synchronization in Android

I want to implement the observer pattern in Android. The observable and observers have to work in their own threads (HandlerThread). The observable object produces some results and notifies their observers every milliseconds. The observers register by passing themselves and Handler reference as arguments.
Example code:
public class Observable {
public interface Observer {
void notify(List<Object> results);
}
private HandlerThread handlerThread;
private List<Object> results = new ArrayList<>();
private final Map<Observer, ObserverWrapper> observers = new HashMap<>();
private void working() {
//Critial section...
//modifying results list...
synchronized (observers) {
for (ObserverWrapper wrapper : observers.values()) {
wrapper.notify(results);
}
}
}
public void register(Observer observer, Handler handler) {
synchronized (observers) {
//Create observer wrapper and add to map here...
}
}
public void unregister(Observer observer) {
synchronized (observers) {
//Remove observer from the map...
}
}
private static final class ObserverWrapper {
private final Observer observer;
private final Handler handler;
public ObserverWrapper(Observer observer, Handler handler) {
this.observer = observer;
this.handler = handler;
}
public void notify(final List<Object> results) {
//The observable thread
handler.post(new Runnable() {
void run() {
//The observer thread
//Critical section...
observer.notify(results);
}
});
}
}
}
The question is: how to synchronize results list that is passed to all observers? I cannot use a copy for each observer because it would cause high memory usage.
There are three options I can think of:
Use the results object as a monitor. That requires minimum changes but this a) not very clean as object itself doesn't say anything about being a monitor. b) Given that the updates are coming every few milliseconds, there is a concern that observer threads will be locking the producer thread for extended periods of time. Both producer and the observer will have to:
synchronized(results) {
// ...
}
Pass an explicit lock object to notify() and use it explicitely:
private final Object lock = new Object();
synchronized(lock) {
// Update results
}
...
synchronized(lock) {
// Read results
}
You mentioned that you don't want to copy results to reduce GC footprint, but this can be the most concurrent option. I'd do it if I were writing it. There is actually a better option, more optimistic option in terms of memory, which is CopyOnWriteArrayList, it will only copy if there is a simultaneous read and write:
https://developer.android.com/reference/java/util/concurrent/CopyOnWriteArrayList.html
Based on the discussions, here is the most concurrent way to do it:
private void working() {
//Critial section...
//modifying results list...
// Create a copy for observers to process
List resultsToProcess = new ArrayList(results);
synchronized (observers) {
for (ObserverWrapper wrapper : observers.values()) {
wrapper.notify(resultsToProcess);
}
}
}

Thread-Safe Access Counter

I am trying to implement Thread Safe Access Counter. What I need to do is create a HashMap which contains the path and integer(Counter). It has two methods which checks whether the map contains the path or not and accordingly increases the count if the path occurs as shown below
public class AccessCounter {
private HashMap<Integer,java.nio.file.Path> counter= new HashMap<Integer,java.nio.file.Path>();
private ReentrantLock lock = new ReentrantLock();
private Path path ;
private RequestHandler rq;
public void map(HashMap<Integer,java.nio.file.Path> counter){
counter.put(10,Paths.get("/Users/a.html"));
counter.put(5, Paths.get("b.html"));
counter.put(2, Paths.get("c.txt"));
counter.put(7, Paths.get("d.txt"));
}
public void increment(){
lock.lock();
System.out.println("Lock Obtained");
try{
if(counter.keySet().equals(rq.fileName())){
for(Integer key: counter.keySet()){
Path text = counter.get(key);
key++;
}
}
else {
counter.put(1,path);
}
}finally{
lock.unlock();
System.out.println("Lock released");
}
}
public void getCount(){
lock.lock();
System.out.println("Lock Obtained");
try{
if(counter.keySet().equals(rq.fileName())){
for(Integer key: counter.keySet()){
Path text = counter.get(key);
key++;
}
}
else {
return ;
}
}finally{
lock.unlock();
System.out.println("Lock released");
}
}
}
RequestHandler(Runnable Class) -> Run() -> picks up one of the files and calls increment method and getCount(). In main method I have to create multiple thread s to AccessCounter concurrently. Could anyone suggest me the right direction. I am doing something wrong but havent able to find it.
public class RequestHandler implements Runnable {
private AccessCounter ac;
private File file;
public void select(File file) {
File file1 = new File("a.html");
File file2 = new File("b.html");
File file3 = new File("a.txt");
}
public File fileName() {
return file;
}
public void run() {
select(file);
ac.increment();
ac.getCount();
}
public static void main(String[] args) {
Thread thread1 = new Thread(new RequestHandler());
thread1.start();
Thread thread2 = new Thread(new RequestHandler());
thread2.start();
}
}
Using a ConcurrentHashMap and a AtomicLong is all you need for thread safety and simplicity.
final ConcurrentMap<Path, AtomicLong> counterMap = new ConcurrentHashMap<>();
public void incrementFor(Path path) {
counterMap.computeIfAbsent(path, p -> new AtomicLong()).incrementAndGet();
}
public long getCount(Path path) {
AtomicLong l = counterMap.get(path);
return l == null ? 0 : l.get();
}
computeIfAbsent will place a new AtomicLong as required in a thread safe manner.
Note: as ConcurrentMap supports concurrent access, you can have many thread using this Map at the same time (provided they are accessing a different Path)
private HashMap counter= new
HashMap();
Instead of HashMap<Integer,java.nio.file.Path> you need to have HashMap<java.nio.file.Path, Integer>, as your intend is to have the count of number of entries with same Path.
A good optimization I see, unless you want to try with normal HashMap and lock in the user code:
You can use ConcurrentHashMap<Path, AtomicInteger> instead of HashMap<..> above.
ConcurrentHashMap has a putIfAbsent(...) method that performs it atomically in a single statement.
AtomicInteger allows us to increment atomically using incrementAndGet method.
Both without extra locks/synchronization in the user code.

java access an object in different threads

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.

Do I need synchronise on objects which guarantee happen-before?

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.

Categories