synchronization of read parallel , write one at a time - java

I have a object obj that is read by many threads frequently , but updated by only one thread periodically.The update happens after long some interval (say 10 minutes).
The data is less transnational.Meaning if read threads gets stale data(old) for some time then its perfectly ok.
Now i thought of using following approach for synchronization:
final Object lock = new Object();
private MyObject obj = new MyObject(); //this is the data
public String getDataFieldName(){
synchronized(lock){
return this.obj.name;
}
}
/*the following code is wrong right?As its just synchronizes the code for getting reference.But after getting reference read thread R1 may try to get data while write Thread is modifying data.Will that give exception?How to solve this? */
public String getData(){
synchronized(lock){
return this.obj;
}
}
//only one thread can update.But how multipe threads can read at once?
public updateData(args ) {
synchronized(lock){
//do update
}
}
My questions are as follows:
I dont want only one thread to read the data.Reads should be parallel.
How can i synchronize read and write ?If write thread is updating and read thread is reading i dont what to get some exception.It is ok if read gets some old data
3)If read thread is reading while write thread is updating , will i get exception?Will there be any problem?

You don't need any synchronization in this scenario. All you have to do is the following:
Make sure MyObject is immutable, meaning that you never change any values in your object Instead you construct a new MyData object everytime you change it. This prevents anyone from seeing a half-changed object.
Declare obj as volatile, to make sure all threads see the updated value everytime.
You will never get an exception because of concurrent reads and writes if you follow these steps.

Use volatile keyword, that will not take the lock, unlike synchronization does, and will provide multiple access, reflecting the updates of one thread to the another..
But then its always better to have some sort of synchronization, as volatile will not ensure to prevent the Race Condition on the data. So if you dont want to use synchronization, then better go with Immutable object
Eg:
import java.util.Date;
/**
* Planet is an immutable class, since there is no way to change
* its state after construction.
*/
public final class Planet {
//Final primitive data is always immutable.
private final double fMass;
private final String fName;
private final Date fDateOfDiscovery;
public Planet (double aMass, String aName, Date aDateOfDiscovery) {
fMass = aMass;
fName = aName;
//make a private copy of aDateOfDiscovery
//this is the only way to keep the fDateOfDiscovery
//field private, and shields this class from any changes that
//the caller may make to the original aDateOfDiscovery object
fDateOfDiscovery = new Date(aDateOfDiscovery.getTime());
}
public double getMass() {
return fMass;
}
public String getName() {
return fName;
}
public Date getDateOfDiscovery() {
return new Date(fDateOfDiscovery.getTime());
}
}

Related

Java thread safety - multiple atomic operations?

I'm just a non-developer playing to be a developer, so my question may be extremely simple!
I'm just testing Java multi-threading stuff, this is not real code. I wonder how to make two member variables update at the same time in Java, in case we want them both in sync. As an example:
public class Testing
{
private Map<String, Boolean> itemToStatus = new ConcurrentHashMap<>();
private Set<String> items = ConcurrentHashMap.newKeySet();
public static void main(String[] args)
{
(new Testing()).start("ABC");
}
public void start(String name) {
if (name.equals("ABC")) {
itemToStatus.put(name, true);
items.add(name);
}
}
}
In that scenario (imagine multi-threaded, of course) I want to be able to guarantee that any reads of items and itemToStatus always return the same.
So, if the code is in the line itemToStatus.put(name, true), and other thread asks items.contains(name), it will return false. On the other hand, if that other thread asks itemToStatus.containsKey(name); it will return true. And I don't want that, I want them both to give the same value, if that makes sense?
How can I make those two changes atomic? Would this work?
if (name.equals("ABC")) {
synchronised(this) {
itemToStatus.put(name, true);
items.add(name);
}
}
Still, I don't see why that would work. I think that's the case where you need a lock or something?
Cheers!
Just synchronizing the writes won't work. You would also need to synchronize (on the same object) the read access to items and itemToStatus collections. That way, no thread could be reading anything if another thread were in the process of updating the two collections. Note that synchronizing in this way means you don't need ConcurrentHashMap or ConcurrentHashSet; plain old HashMap and HashSet will work because you're providing your own synchronization.
For example:
public void start(String name) {
if (name.equals("ABC")) {
synchronized (this) {
itemToStatus.put(name, true);
items.add(name);
}
}
}
public synchronized boolean containsItem(String name) {
return items.contains(name);
}
public synchronized boolean containsStatus(String name) {
return itemToStatus.containsKey(name);
}
That will guarantee that the value returned by containsItem would also have been returned by containsStatus if that call had been made instead. Of course, if you want the return values to be consistent over time (as in first calling containsItem() and then containsStatus()), you would need higher-level synchronization.
The short answer is yes: by synchronizing the code block, as you did in your last code snippet, you made the class thread-safe because that code block is the only one that reads or modifies the status of the class (represented by the two instance variables).
The meaning of synchronised(this) is that you use the instance of the object (this) as a lock: when a thread enters that code block it gets the lock, preventing other threads to enter the same code block until the thread releases it when it exits from the code block.

Java Multithreading Execution Blocked

for learning purpose i have tried to implements a queue data-structure + Consumer/producer chain that is thread-safe, for learning purpose too i have not used notify/wait mechanism :
SyncQueue :
package syncpc;
/**
* Created by Administrator on 01/07/2009.
*/
public class SyncQueue {
private int val = 0;
private boolean set = false;
boolean isSet() {
return set;
}
synchronized public void enqueue(int val) {
this.val = val;
set = true;
}
synchronized public int dequeue() {
set = false;
return val;
}
}
Consumer :
package syncpc;
/**
* Created by Administrator on 01/07/2009.
*/
public class Consumer implements Runnable {
SyncQueue queue;
public Consumer(SyncQueue queue, String name) {
this.queue = queue;
new Thread(this, name).start();
}
public void run() {
while(true) {
if(queue.isSet()) {
System.out.println(queue.dequeue());
}
}
}
}
Producer :
package syncpc;
import java.util.Random;
/**
* Created by Administrator on 01/07/2009.
*/
public class Producer implements Runnable {
SyncQueue queue;
public Producer(SyncQueue queue, String name) {
this.queue = queue;
new Thread(this, name).start();
}
public void run() {
Random r = new Random();
while(true) {
if(!queue.isSet()) {
queue.enqueue(r.nextInt() % 100);
}
}
}
}
Main :
import syncpcwn.*;
/**
* Created by Administrator on 27/07/2015.
*/
public class Program {
public static void main(String[] args) {
SyncQueue queue = new SyncQueue();
new Producer(queue, "PROCUDER");
new Consumer(queue, "CONSUMER");
}
}
The problem here, is that if isSet method is not synchronized , i got an ouput like that :
97,
55
and the program just continue running without outputting any value. while if isSet method is synchronized the program work correctly.
i don't understand why, there is no deadlock, isSet method just query the set instance variable without setting it, so there is no race condition.
set needs to be volatile:
private boolean volatile set = false;
This ensures that all readers see the updated value when a write completes. Otherwise they will end up seeing the cached value. This is discussed in more detail in this article on concurrency, and also provides examples of different patterns that use volatile.
Now the reason that your code works with synchronized is probably best explained with an example. synchronized methods can be written as follows (i.e., they are equivalent to the following representation):
public class SyncQueue {
private int val = 0;
private boolean set = false;
boolean isSet() {
synchronized(this) {
return set;
}
}
public void enqueue(int val) {
synchronized(this) {
this.val = val;
set = true;
}
}
public int dequeue() {
synchronized(this) {
set = false;
return val;
}
}
}
Here, the instance is itself used as a lock. This means that only thread can hold that lock. What this means is that any thread will always get the updated value because only one thread could be writing the value, and a thread that wants to read set won't be able to execute isSet until the other thread releases the lock on this, at which point the value of set will have been updated.
If you want to understand concurrency in Java properly you should really read Java: Concurrency In Practice (I think there's a free PDF floating around somewhere as well). I'm still going through this book because there are still many things that I do not understand or am wrong about.
As matt forsythe commented, you will run into issues when you have multiple consumers. This is because they could both check isSet() and find that there is a value to dequeue, which means that they will both attempt to dequeue that same value. It comes down to the fact that what you really want is for the "check and dequeue if set" operation to be effectively atomic, but it is not so the way you have coded it. This is because the same thread that initially called isSet may not necessarily be the same thread that then calls dequeue. So the operation as a whole is not atomic which means that you would have to synchronize the entire operation.
The problem you have is visibility (or rather, the lack of it).
Without any instructions to the contrary, the JVM will assume that the value assigned to a variable in one thread need not be visible to the other threads. It may be made visible sometimes later (when it's convenient to do so), or maybe not ever. The rules governing what should be made visible and when are defined by the Java Memory Model and they're summed up here. (They may be a bit dry and scary at first, but it's absolutely crucial to understand them.)
So even though the producer sets set to true, the consumer will continue to see it as false. How can you publish a new value?
Mark the field as volatile. This works well for primitive values like boolean, with references you have to be a bit more careful.
synchronized provides not just mutual exclusion but also guarantees that any values set in it will be visible to anyone entering a synchronized block that uses the same object. (This is why everything works if you declare the isSet() method synchronized.)
Using a thread-safe library class, like the Atomic* classes of java.util.concurrent
In your case volatile is probably the best solution because you're only updating a boolean, so atomicity of the update is guaranteed by default.
As #matt forsythe pointed out, there is also a TOCTTOU issue with your code too because your threads can be interrupted by another between isSet() and enqueue()/dequeue().
I assume that when we get stuck in threading issue, the first step was to make sure that both the threads are running well. ( i know they will as there are no locks to create deadlock)
For that you could have added a printf statement in enqueue function as well. That would make sure that enqueue and dequeue threads are running well.
Then second step should have been that "set" is the shared resource, so is the value toggling well enough so that code can run in desired fashion.
I think if you could reason and put the logging well enough, you can realize the issues in problem.

Implementation of singleton thread-safe list

I'm using Spring framework. Need to have a list of objects, which should get all data from database at once. When data is changed, list will be null and next get operation should fill data from database again. Is my code correct for multi-thread environment?
#Component
#Scope("singleton")
public class MyObjectHolder {
private volatile List<MyObject> objectList = null;
public List<MyObject> getObjectList() {
if (objectList == null) {
synchronized (objectList) {
if (objectList == null) {
objectList = getFromDB();
}
}
}
return objectList;
}
synchronized
public void clearObjectList() {
objectList = null;
}
}
Short answer: no.
public class MyObjectHolder {
private final List<MyObject> objectList = new List<>();
public List<MyObject> getObjectList() {
return objectList;
}
This is the preferred singleton pattern.
Now you need to figure out how to get the data into the list in a thread-safe way. For this Java already has some pre-made thread-safe lists in the concurrent package, which should be preferred to any synchronized implementation, as they are much faster under heavy threading.
Your problem could be solved like this:
public class MyObjectHolder {
private final CopyOnWriteArrayList<MyObject> objectList = new CopyOnWriteArrayList<>();
public List<MyObject> getObjectList() {
return objectList;
}
public boolean isEmtpy() {
return objectList.isEmpty();
}
public void readDB() {
final List<MyObject> dbList = getFromDB();
// ?? objectList.clear();
objectList.addAll(dbList);
}
}
Please note the absence of any synchronized, yet the thing is completely thread-safe. Java guarantees that the calls on that list are performed atomically. So I can call isEmpty() while someone else is filling up the list. I will only get a snapshot of a moment in time and can't tell what result I will get, but it will in all cases succeed without error.
The DB call is first written into a temporary list, therefore no threading issues can happen here. Then the addAll() will atomically move the content into the real list, again: all thread-safe.
The worst-case scenario is that Thread A is just about done writing the new data, while at the same time Thread B checks if the list contains any elements. Thread B will receive the information that the list is empty, yet a microsecond later it contains tons of data. You need to deal with this situation by either repeatedly polling or by using an observer pattern to notify the other threads.
No, your code is not thread safe. For example, you could assign objectList in one thread at time X, but set it to null (via clearObjectList()) at time X+1 because you are synchronizing on 2 different objects. The first synchronization is on objectList itself and the second synchronization is on the instance of MyObjectHolder. You should look into locks when using a shared resource instead of using synchonize, specifically something like a ReadWriteLock.

Is a direct assignment of a volatile variable thread safe? As safe as an AtomicReference?

Is this as safe as using an AtomicReference?
private volatile String myMember;
public void setMyMember(String s) {
myMember = s;
}
vs.
private final AtomicReference<String> myMember = new AtomicReference<>();
public void setMyMember(String s) {
while (true) {
String current = myMember.get();
if (myMember.compareAndSet(current, s))
break;
}
}
Your code is "safe" but doesn't do the same thing as the AtomicReference code. Typically, the AtomicReference loop with compareAndSet is used when someone is trying to add something to a list or object and they want to protect against the race conditions with multiple threads.
For example:
private final AtomicReference<List<String>> listRef = new AtomicReference<>();
...
while (true) {
List<String> currentList = listRef.get();
List<String> newList = new ArrayList<String>(currentList);
newList.add(stringToAdd);
// if we update the list reference, make sure we don't overwrite another one
if (listRef.compareAndSet(currentList, newList))
break;
}
In your case, since you are using a simple String object, just making it volatile will be fine. There is no point in doing the compareAndSet. If you still want to use AtomicReference, then just call myMember.set(...).
Your first code snippet is completely thread safe and is enough because String is thread safe and assigning to variable is atomic.
The second one doesn't make much sense, such construct is used internally e.g. in AtomicInteger to avoid ignoring assignments in concurrent environment. volatile is fine in your case.

Synchronizing on two or more objects (Java)

I have code similar to following:
public class Cache{
private final Object lock = new Object();
private HashMap<Integer, TreeMap<Long, Integer>> cache =
new HashMap<Integer, TreeMap<Long, Integer>>();
private AtomicLong FREESPACE = new AtomicLong(102400);
private void putInCache(TreeMap<Long, Integer> tempMap, int fileNr){
int length; //holds the length of data in tempMap
synchronized(lock){
if(checkFreeSpace(length)){
cache.get(fileNr).putAll(tmpMap);
FREESPACE.getAndAdd(-length);
}
}
}
private boolean checkFreeSpace(int length){
while(FREESPACE.get() < length && thereIsSomethingToDelete()){
// deleteSomething returns the length of deleted data or 0 if
// it could not delete anything
FREESPACE.getAndAdd(deleteSomething(length));
}
if(FREESPACE.get() < length) return true;
return false;
}
}
putInCache is called by about 139 threads a second. Can I be sure that these two methods will synchronize on both cache and FREESPACE? Also, is checkFreeSpace() multithread-safe i.e can I be sure that there will be only one invocation of this method at a time? Can the "multithread-safety" of this code be improved?
To have your question answered fully, you would need to show the implementations of the thereIsSomethingToDelete() and deleteSomething() methods.
Given that checkFreeSpace is a public method (does it really need to be?), and is unsynchronized, it is possible it could be called by another thread while the synchronized block in the putInCache() method is running. This by itself might not break anything, since it appears that the checkFreeSpace method can only increase the amount of free space, not reduce it.
What would be more serious (and the code sample doesn't allow us to determine this) is if the thereIsSomethingToDelete() and deleteSomething() methods don't properly synchronize their access to the cache object, using the same Object lock as used by putInCache().
You don't usually synchronize on the fields you want to control access to directly.
The fields that you want to synchronize access to must only be accessed from within synchronized blocks (on the same object) to be considered thread safe. You are already doing this in putInCache().
Therefore, because checkFreeSpace() accesses shared state in an unsynchronized fashion, it is not thread safe.

Categories