I'm working on some issue where I have an interface implementation (of GoogleMaps tile provider) in which the method requires its data immediately (not in a callback), but for me to get the data I have to call a method which returns the data in a callback. I have to link these 2 together, and I have something (which I think works, I have yet to test it), but I am worried about some Android Studio warnings I get.
This is the code I've written:
#Override
public Tile getTile(int x, int y, int zoom) {
// If the tile provider is not available, return null
if(tileProvider == null) {
return NO_TILE;
}
// Define the tile request
final TileRequest tileRequest = new TileRequest(tileProvider.getLayer().getTileWidth(), tileProvider.getLayer().getTileHeight());
// Make the call to get the tile data, which, depending on the situation, can possibly
// be handled by another thread.
tileProvider.getTile(x, y, zoom, new GetDataListener<byte[]>() {
#Override
public void onGetData(byte[] data, Exception exception) {
synchronized (tileRequest) {
tileRequest.data = data;
tileRequest.exceptionOccurred = exception != null;
tileRequest.finishedRequest = true;
tileRequest.notify();
}
}
});
synchronized (tileRequest) {
// If, before this statement was reached, the request has already been finished, call and return getTile immediately.
if(tileRequest.finishedRequest) {
return tileRequest.getTile();
} else {
try {
// Wait for the tileRequest to be finished
tileRequest.wait();
// Once it is finished (in the callback a notify is called as soon as its finished, so thats how this code is reached)
// the tile data is available, return the tile
return tileRequest.getTile();
} catch(InterruptedException ex) {
// Exception occurred, return null so GoogleMaps will try it again later
logger.error("Exception in getTile method: {}", ex.getLocalizedMessage());
ex.printStackTrace();
return null;
}
}
}
}
So what Android Studio is giving me, on the second synchronized (tileRequest) { line, is the following warning:
Synchronization on local variable 'tileRequest'
Reports synchronization on a local variable or parameter. Such synchronization has little effect, since different threads usually will have different values for the local variable or parameter. The intent of the code will usually be clearer if synchronization on a field is used.
I am not too confident on my understanding of synchronization, waiting and notifying, so can someone tell me if my approach is valid, regardless of the warning?
EDIT
There were some questions stating that no multiple threads were involved, I updated the comments a bit, but the tileProvider.getTile(...) method gets the tile, but there is no guarantee that this will not happen on another thread.
Synchronizing on a local object may be ignored by the JVM in some situations so you can't count on it having the correct semantics without a detailed analysis. I would suggest a simpler approach:
CountDownLatch done = new CountDownLatch(1);
tileProvider.getTile(x, y, zoom, new GetDataListener<byte[]>() {
#Override
public void onGetData(byte[] data, Exception exception) {
tileRequest.data = data;
tileRequest.exceptionOccurred = exception != null;
tileRequest.finishedRequest = true;
done.countDown();
}
});
done.await();
return tileRequest.getTile();
Note that you probably can't have an if (tileRequest.finishedRequest) return tileRequest.getTile(); before the done.await() because you would lose the visibility guarantee provided by the latch. And based on your code it seems that the latch would be unblocked immediately after finishedRequest is set to true anyway.
Synchronization is required when two threads tries to access and update same resource, and you want only single thread to access the object at any given time.
In your case, tileRequest is a local variable defined in method scope. So each thread will have it's own instance of the object. So synchronizing local variable will just have an overhead of locking the object without any actual multi-threading benefits.
Your code is correct, albeit clunky. Even though you're using a method-local object for synchronization, it's enclosed by GetDataListener, so it'll potentially be shared by different threads.
Take a look at CompletebleFuture. It might make this code more readable.
IMO the compiler warning is over zealous.
Not only that, but it is technically wrong: It is not possible for Java code to synchronize on a variable. Synchronization is something you do to an object.
When you write synchronized (x) { ... }, the x is an expression that is evaluated to yield an object reference. Most programmers expect x to be a private final instance variable or a private final static variable---those are easy cases to understand---but it doesn't have to be that way. x could be a local variable or it could be a method call that returns an object reference.
What's important, is that the object is shared between threads. It doesn't make any sense to synchronize on an object unless some other thread also synchronize on the same object.
The warning message that you're getting is meant to prevent a common newbie mistake. Even if it's technically wrong, it might prevent dozens or hundreds of daily phone calls from confused newbies to some developer help center somewhere.
When I'm working on commercial software, I don't worry as much about whether a decision is "right" or "wrong" as whether it will increase or decrease the number of calls to our support center.
Related
I have two methods as follows:
class A{
void method1(){
someObj.setSomeAttribute(true);
someOtherObj.callMethod(someObj);
}
void method2(){
someObj.setSomeAttribute(false);
someOtherObj.callMethod(someObj);
}
}
where in another place that attribute is evaluated:
class B{
void callMethod(Foo someObj){
if(someObj.getAttribute()){
//do one thing
} else{
//so another thing
}
}
}
Note that A.method1 and A.method2 are updating the attribute of the same object. If those 2 methods are run in 2 threads, will this work or will there be unexpected results?
Will there be unexpected results? Yes, guaranteed, in that if you modify things you wouldn't want to have an impact on your app (such as the phase of the moon, the current song playing in your winamp, whether your dog is cuddling near the CPU, if it's the 5th tuesday of the month, and other such things), that may have an effect on behaviour. Which you don't want.
What you've described is a so-called violation of the java memory model: The end result is that any java implementation is free to return any of multiple values and nevertheless, that VM is operating properly according to the java specification. Even if it does so seemingly arbitrarily.
As a general rule, each thread gets an unfair coin. Unfair, in that it will try to mess with you: It'll flip correctly every time when you test it out, and then in production, and only when you're giving a demo to that crucial customer, it'll get ya.
Every time it reads to or writes from any field, it will flip this mean coin. On heads, it will use the actual field. On tails, it will use a local copy it made.
That's oversimplifying the model quite a bit, but it's a good start to try to get your head around how this works.
The way out is to force so-called 'comes before' relationships: What java will do, is ensure that what you can observe matches these relationships: If event A is defined as having a comes-before relationship vs. event B, then anything A did will be observed, exactly as is, by B, guaranteed. No more coin flips.
Examples of establishing comes-before relationships involve using volatile, synchronized, and any methods that use these things internally.
NB: Of course. if your setSomeAttribute method, which you did not paste, includes some comes-before-establishing act, then there's no problem here, but as a rule a method called setX will not be doing that.
An example of one that doesn't:
class Example {
private String attr;
public void setAttr(String attr) {
this.attr = attr;
}
}
some examples of ones that do:
Let's say method B.callMethod is executed in the same thread as method1 - then you are guaranteed to at least observe the change method1 made, though it's still a coin flip (whether you actually see what method2 did or not). What would not be possible is seeing the value of that attribute before either method1 or method2 runs, because code running in a single thread has comes-before across the entire run (any line that is executed before another in the same thread has a comes-before relationship).
The set method looks like:
class Example {
private String attr;
private final Object lock = new Object();
public void setAttr(String attr) {
synchronized (lock) {
this.attr = attr;
}
}
public String getAttr() {
synchronized (lock) {
return this.attr;
}
}
}
Now the get and set ops lock on the same object, that's one of the ways to establish comes-before. Which thread got to a lock first is observable behaviour; if method1's set got there before B's get, then you are guaranteed to observe method1's set.
More generally, sharing state between threads is extremely tricky and you should endeavour not do so. The alternatives are:
Initialize all state before starting a thread, then do the job, and only when it is finished, relay all results back. Fork/join does this.
Use a messaging system that has great concurrency fundamentals, such as a database, which has transactions, or message queue libraries.
If you must share state, try to write things in terms of the nice classes in j.u.concurrent.
I assume what you expected is when you call A.method1, someObj.getAttribute() will return true in B.callMethod, when you call A.method2, someObj.getAttribute() will return false in B.callMethod.
Unfortunately,this will not work. Because between the line setSomeAttribute and callMethod,other thread may have change the value of the attribute.
If you are only use the attribute in callMethod,why not just pass the attribute instead of the Foo object. Code as follow:
class A{
void method1(){
someOtherObj.callMethod(true);
}
}
class B{
void callMethod(boolean flag){
if(flag){
//do one thing
} else{
//so another thing
}
}
}
If you must use Foo as the parameter, what you can do is to make setAttribute and callMethod atomic.
The easiest way to achieve it is to make it synchronized.Code as follow:
synchronized void method1(){
someObj.setSomeAttribute(true);
someOtherObj.callMethod(someObj);
}
synchronized void method2(){
someObj.setSomeAttribute(false);
someOtherObj.callMethod(someObj);
}
But this may have bad performance, you can achieve it with some more fine-grained lock.
How would you answer the following question?
A method of a java class contains a block of code that must be
executed atomically. Explain, using appropriate pseudo-code, how you
would ensure that this block of code is executed atomically
Would I achieve this by making the method ..
public final AtomicInteger x = new AtomicInteger(0);
then ensuring the get statement returned:
x.get()
and if I wanted to increment the value of x would I do this?
x.getAndIncrement();
The answer depends on your definition of "atomic"
I know of three valid definitions for atomic:
Atomic as in synchronized: only one thread can be executing the code at one time;
Atomic as in ACID: all of the action/block happens, or none of it does;
Atomic as in uninterruptible: once the block starts, it can't be interrupted, even by task switching.
The first is probably what your professor meant, and it's pretty easy to accomplish (see below).
The second (atomic as in ACID) can be approximated. See below.
The third simply cannot be guaranteed in Java - it doesn't provide access to the "critical sections" primitives required for uninterruptibility. Fortunately, the need for this is pretty much restricted to operating systems and device drivers.
Atomic as in synchronized
This is relatively straightforward: simply enclose your block of code in a synchronized block. I've shown it as a discrete block below, but there are other options:
public void doSomethingQuasiAtomic() {
synchronized (exampleLock) {
// Your code block goes here.
// Only one thread will ever be in this block at a time.
...
}
}
Atomic as in ACID
There's no general-case solution for ACID atomicity, but it can be approximated, also using synchronized code. In order to do this, each of the parts of the action must be safely reversible.
This is how I'd approach it:
For the sake of argument, assume there's a multipart action you need to do on an object we'll call exampleObj, that you have three actions to be performed which can be safely reversed, and that all access to example is synchronized on exampleLock.
synchronized(exampleLock) {
boolean actionOneDone=false;
boolean actionTwoDone=false;
boolean actionThreeDone=false;
try {
actionOneDone=doActionOne(exampleObj); // or perhaps exampleObj.doActionOne();
if(actionOneDone) actionTwoDone=doActionTwo(exampleObj);
if(actionTwoDone) actionThreeDone=doActionThree(exampleObj);
} catch (Exception ex) {
// Whatever seems appropriate here.
} finally {
if (! (actionOneDone && actionTwoDone && actionThreeDone)) {
/* At least one part failed. Back out the completed actions in reverse order.
* Note that we never need to reverse action three since if it completed, so did the others.
*/
if (actionTwoDone) {
reverseActionTwo(exampleObj); // or perhaps exampleObj.reverseActionTwo();
}
if (actionOneDone) {
reverseActionOne(exampleObj);
}
}
}
}
I believe that the expected answer was something like this:
public class A {
public void foo() {
// .. some code
doSomething(); // the critical part
// .. come code
}
public synchronized void doSomething() { // this is a synchronized method
// the critical code
}
}
The execution of doSomething() is not really atomic (Disclaimer: it's very different from atomicity), but the synchronized keyword ensures that only one thread can enter the execution of this method (on one instance of A). I think that is what they meant instead of atomicity.
Here is another question about atomicity in Java. You may find something useful in there.
I think I have a fairly firm grasp on using the synchronized keyword to prevent inconsistencies between threads in java, but I don't fully understand what happens if you don't use that keyword.
Say for instance that I have a field accessed/modified by two threads:
private String sharedString = "";
class OneThread extends Thread {
private Boolean mRunning = false;
public OneThread() {}
public synchronized setRunning(Boolean b) {
mRunning = b;
}
#Override
public void run() {
while (mRunning) {
// read or write to shared string
sharedString = "text from thread 1";
System.out.println("String seen from thread 1: " + sharedString);
super.run();
}
}
}
class AnotherThread extends Thread {
private Boolean mRunning = false;
public AnotherThread() {}
public synchronized setRunning(Boolean b) {
mRunning = b;
}
#Override
public void run() {
while (mRunning) {
// read or write to shared string
sharedString = "text from thread 2";
System.out.println("String seen from thread 2: " + sharedString);
super.run();
}
}
}
Since both of these threads are accessing and modifying the field sharedString without using the synchronized keyword, I would expect inconsistencies. What I am wondering is what actually happens though. While debugging, I have stepped carefully through both threads in situations like this and noticed that even while one thread is paused, it's state can be "sticky".
For the sake of the above example, suppose both threads are paused in the debugger. If I step through one of the threads and leave the other paused, I would expect it would operate like a single threaded application. Yet, many times right after modifying the field, the next line that accesses it retrieves the "wrong" value (a value inconsistent with what it was just modified to).
I know that this code is not good.. but I am asking the question because I'm hoping someone could provide an answer that gives some insight into what actually happens in the virtual machine when multi-threaded applications are implemented poorly. Does the thread who's field modification attempt was unsuccessful have any effect at all?
If after poorly implementing multi-threaded code we are simply in the realm of "undefined" behavior, and there is no value in learning about this behavior, I'm ok with that.. just a multi-threading noob trying to understand what I observe in the debugger.
This is due to another critical function of synchronization across threads in Java: preventing data staleness. As part of the Java Memory Model, a Java thread may cache values for shared data. There is no guarantee that a thread will ever see updates made by another thread unless either the shared mutable data is accessed in synchronized blocks or it is marked as volatile. See here for more information.
There's really no way for the printout to be "wrong" if there is no other thread that can change the shared value (as would be the case if there are really only 2 threads and one is definitely paused). Can you by chance provide the code that "kicks off" these 2 threads (i.e. your main)?
So I've been reading on concurrency and have some questions on the way (guide I followed - though I'm not sure if its the best source):
Processes vs. Threads: Is the difference basically that a process is the program as a whole while a thread can be a (small) part of a program?
I am not exactly sure why there is a interrupted() method and a InterruptedException. Why should the interrupted() method even be used? It just seems to me that Java just adds an extra layer of indirection.
For synchronization (and specifically about the one in that link), how does adding the synchronize keyword even fix the problem? I mean, if Thread A gives back its incremented c and Thread B gives back the decremented c and store it to some other variable, I am not exactly sure how the problem is solved. I mean this may be answering my own question, but is it supposed to be assumed that after one of the threads return an answer, terminate? And if that is the case, why would adding synchronize make a difference?
I read (from some random PDF) that if you have two Threads start() subsequently, you cannot guarantee that the first thread will occur before the second thread. How would you guarantee it, though?
In synchronization statements, I am not completely sure whats the point of adding synchronized within the method. What is wrong with leaving it out? Is it because one expects both to mutate separately, but to be obtained together? Why not just have the two non-synchronized?
Is volatile just a keyword for variables and is synonymous with synchronized?
In the deadlock problem, how does synchronize even help the situation? What makes this situation different from starting two threads that change a variable?
Moreover, where is the "wait"/lock for the other person to bowBack? I would have thought that bow() was blocked, not bowBack().
I'll stop here because I think if I went any further without these questions answered, I will not be able to understand the later lessons.
Answers:
Yes, a process is an operating system process that has an address space, a thread is a unit of execution, and there can be multiple units of execution in a process.
The interrupt() method and InterruptedException are generally used to wake up threads that are waiting to either have them do something or terminate.
Synchronizing is a form of mutual exclusion or locking, something very standard and required in computer programming. Google these terms and read up on that and you will have your answer.
True, this cannot be guaranteed, you would have to have some mechanism, involving synchronization that the threads used to make sure they ran in the desired order. This would be specific to the code in the threads.
See answer to #3
Volatile is a way to make sure that a particular variable can be properly shared between different threads. It is necessary on multi-processor machines (which almost everyone has these days) to make sure the value of the variable is consistent between the processors. It is effectively a way to synchronize a single value.
Read about deadlocking in more general terms to understand this. Once you first understand mutual exclusion and locking you will be able to understand how deadlocks can happen.
I have not read the materials that you read, so I don't understand this one. Sorry.
I find that the examples used to explain synchronization and volatility are contrived and difficult to understand the purpose of. Here are my preferred examples:
Synchronized:
private Value value;
public void setValue(Value v) {
value = v;
}
public void doSomething() {
if(value != null) {
doFirstThing();
int val = value.getInt(); // Will throw NullPointerException if another
// thread calls setValue(null);
doSecondThing(val);
}
}
The above code is perfectly correct if run in a single-threaded environment. However with even 2 threads there is the possibility that value will be changed in between the check and when it is used. This is because the method doSomething() is not atomic.
To address this, use synchronization:
private Value value;
private Object lock = new Object();
public void setValue(Value v) {
synchronized(lock) {
value = v;
}
}
public void doSomething() {
synchronized(lock) { // Prevents setValue being called by another thread.
if(value != null) {
doFirstThing();
int val = value.getInt(); // Cannot throw NullPointerException.
doSecondThing(val);
}
}
}
Volatile:
private boolean running = true;
// Called by Thread 1.
public void run() {
while(running) {
doSomething();
}
}
// Called by Thread 2.
public void stop() {
running = false;
}
To explain this requires knowledge of the Java Memory Model. It is worth reading about in depth, but the short version for this example is that Threads have their own copies of variables which are only sync'd to main memory on a synchronized block and when a volatile variable is reached. The Java compiler (specifically the JIT) is allowed to optimise the code into this:
public void run() {
while(true) { // Will never end
doSomething();
}
}
To prevent this optimisation you can set a variable to be volatile, which forces the thread to access main memory every time it reads the variable. Note that this is unnecessary if you are using synchronized statements as both keywords cause a sync to main memory.
I haven't addressed your questions directly as Francis did so. I hope these examples can give you an idea of the concepts in a better way than the examples you saw in the Oracle tutorial.
I have a multithreaded class A which accesses the following insert() method of another class B (A has only a single instance of B).
Instead of making the entire method synchronized, are there any better ways to synchronize the following method? (to reduce the synchronization overhead)
private void insert(byte[] shardKey, byte[] queueKey,
byte[] value, PipelineMessageType msgType) {
PipelineMessage pipelineMessage = new PipelineMessage(queueKey,
value, msgType);
LinkedBlockingQueue<PipelineMessage> queue;
JedisShardInfo shardInfo = shardedJedis.getShardInfo(shardKey); // shardedJedis is an instance variable of this class
String mapKey = shardInfo.getHost() + shardInfo.getPort();
queue = shardQueue.get(mapKey); // shardQueue is an instance variable of this class
boolean insertSuccessful = queue.offer(pipelineMessage);
if(!insertSuccessful) {
// perform the pipeline sync - flush the queue
// use another thread for this
// (processing of queue entries is given to another thread here)
// queue would be empty now. Insert (k,v)
queue.offer(pipelineMessage);
}
}
I tried to synchronize only the fragment which accesses the instance variables but there might be a scenario where 2 threads try to insert into a full queue and enter the if block. Then 2 threads might process the queue entries which I don't want to happen.
Any suggestions are appreciated. Thank you in advance.
Seems to me that if JedisShardInfo would be a read-only item, then you should need to protect/synchronize it. So you could synchronize only from the line
queue= ...
Otherwise, almost everything should be synchronized, except the first statement (declaration of pipeline message), and then I really wonder if it changes much compared to declaring the whole method synchronized.
Also, if you got other points of synchronization, I mean other methods or block codes that are synchronized on this, you should consider splitting them and synchronize on different data members of this depending on which data members you wish to protect from multi-threading :
Object lockerA = new Object() {};
synchronized( lockerA )
{}//sync
Well, not much to say. :)
Regards,
Stéphane
The key to correct synchronization is to follow this pattern:
synchronize(lockObjectForState) { // All code that alters state must also synchronise on the same lock
while(!stateOkToProceed()) {
try {
lockForState.wait();
} catch (InterruptedException e) {
// handle if your thread was interrupted deliberately as a single to exit, or spuriously (in which case do nothing)
}
}
updateState();
lockForState.notifyAll();
}
java.util.concurrent package offer many thread-safe implementations of classes needed to solve common threading problems. Consider using a BlockingQueue.