Asked  7 Months ago    Answers:  5   Viewed   36 times

I am wondering at the difference between declaring a variable as volatile and always accessing the variable in a synchronized(this) block in Java?

According to this article http://www.javamex.com/tutorials/synchronization_volatile.shtml there is a lot to be said and there are many differences but also some similarities.

I am particularly interested in this piece of info:

...

  • access to a volatile variable never has the potential to block: we're only ever doing a simple read or write, so unlike a synchronized block we will never hold on to any lock;
  • because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we're prepared to "miss an update");

What do they mean by read-update-write? Isn't a write also an update or do they simply mean that the update is a write that depends on the read?

Most of all, when is it more suitable to declare variables volatile rather than access them through a synchronized block? Is it a good idea to use volatile for variables that depend on input? For instance, there is a variable called render that is read through the rendering loop and set by a keypress event?

 Answers

90

It's important to understand that there are two aspects to thread safety.

  1. execution control, and
  2. memory visibility

The first has to do with controlling when code executes (including the order in which instructions are executed) and whether it can execute concurrently, and the second to do with when the effects in memory of what has been done are visible to other threads. Because each CPU has several levels of cache between it and main memory, threads running on different CPUs or cores can see "memory" differently at any given moment in time because threads are permitted to obtain and work on private copies of main memory.

Using synchronized prevents any other thread from obtaining the monitor (or lock) for the same object, thereby preventing all code blocks protected by synchronization on the same object from executing concurrently. Synchronization also creates a "happens-before" memory barrier, causing a memory visibility constraint such that anything done up to the point some thread releases a lock appears to another thread subsequently acquiring the same lock to have happened before it acquired the lock. In practical terms, on current hardware, this typically causes flushing of the CPU caches when a monitor is acquired and writes to main memory when it is released, both of which are (relatively) expensive.

Using volatile, on the other hand, forces all accesses (read or write) to the volatile variable to occur to main memory, effectively keeping the volatile variable out of CPU caches. This can be useful for some actions where it is simply required that visibility of the variable be correct and order of accesses is not important. Using volatile also changes treatment of long and double to require accesses to them to be atomic; on some (older) hardware this might require locks, though not on modern 64 bit hardware. Under the new (JSR-133) memory model for Java 5+, the semantics of volatile have been strengthened to be almost as strong as synchronized with respect to memory visibility and instruction ordering (see http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile). For the purposes of visibility, each access to a volatile field acts like half a synchronization.

Under the new memory model, it is still true that volatile variables cannot be reordered with each other. The difference is that it is now no longer so easy to reorder normal field accesses around them. Writing to a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire. In effect, because the new memory model places stricter constraints on reordering of volatile field accesses with other field accesses, volatile or not, anything that was visible to thread A when it writes to volatile field f becomes visible to thread B when it reads f.

-- JSR 133 (Java Memory Model) FAQ

So, now both forms of memory barrier (under the current JMM) cause an instruction re-ordering barrier which prevents the compiler or run-time from re-ordering instructions across the barrier. In the old JMM, volatile did not prevent re-ordering. This can be important, because apart from memory barriers the only limitation imposed is that, for any particular thread, the net effect of the code is the same as it would be if the instructions were executed in precisely the order in which they appear in the source.

One use of volatile is for a shared but immutable object is recreated on the fly, with many other threads taking a reference to the object at a particular point in their execution cycle. One needs the other threads to begin using the recreated object once it is published, but does not need the additional overhead of full synchronization and it's attendant contention and cache flushing.

// Declaration
public class SharedLocation {
    static public SomeObject someObject=new SomeObject(); // default object
    }

// Publishing code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
//       someObject will be internally consistent for xxx(), a subsequent 
//       call to yyy() might be inconsistent with xxx() if the object was 
//       replaced in between calls.
SharedLocation.someObject=new SomeObject(...); // new object is published

// Using code
private String getError() {
    SomeObject myCopy=SharedLocation.someObject; // gets current copy
    ...
    int cod=myCopy.getErrorCode();
    String txt=myCopy.getErrorText();
    return (cod+" - "+txt);
    }
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.

Speaking to your read-update-write question, specifically. Consider the following unsafe code:

public void updateCounter() {
    if(counter==1000) { counter=0; }
    else              { counter++; }
    }

Now, with the updateCounter() method unsynchronized, two threads may enter it at the same time. Among the many permutations of what could happen, one is that thread-1 does the test for counter==1000 and finds it true and is then suspended. Then thread-2 does the same test and also sees it true and is suspended. Then thread-1 resumes and sets counter to 0. Then thread-2 resumes and again sets counter to 0 because it missed the update from thread-1. This can also happen even if thread switching does not occur as I have described, but simply because two different cached copies of counter were present in two different CPU cores and the threads each ran on a separate core. For that matter, one thread could have counter at one value and the other could have counter at some entirely different value just because of caching.

What's important in this example is that the variable counter was read from main memory into cache, updated in cache and only written back to main memory at some indeterminate point later when a memory barrier occurred or when the cache memory was needed for something else. Making the counter volatile is insufficient for thread-safety of this code, because the test for the maximum and the assignments are discrete operations, including the increment which is a set of non-atomic read+increment+write machine instructions, something like:

MOV EAX,counter
INC EAX
MOV counter,EAX

Volatile variables are useful only when all operations performed on them are "atomic", such as my example where a reference to a fully formed object is only read or written (and, indeed, typically it's only written from a single point). Another example would be a volatile array reference backing a copy-on-write list, provided the array was only read by first taking a local copy of the reference to it.

Tuesday, June 1, 2021
 
OMGKurtNilsen
answered 7 Months ago
92

The names are pretty much self-explanatory, to me. Spliterator == Splittable Iterator : it can split some source, and it can iterate it too. It roughly has the same functionality as an Iterator, but with the extra thing that it can potentially split into multiple pieces: this is what trySplit is for. Splitting is needed for parallel processing.

An Iterator always has an unknown size: you can traverse elements only via hasNext/next; a Spliterator can provide the size (thus improving other operations too internally); either an exact one via getExactSizeIfKnown or a approximate via estimateSize.

On the other hand, tryAdvance is what hasNext/next is from an Iterator, but it's a single method, much easier to reason about, IMO. Related to this, is forEachRemaining which in the default implementation delegates to tryAdvance, but it does not have to always be like this (see ArrayList for example).

A Spliterator also is a "smarter" Iterator, via its internal properties like DISTINCT or SORTED, etc (which you need to provide correctly when implementing your own Spliterator). These flags are used internally to disable unnecessary operations; see for example this optimization:

 someStream().map(x -> y).count();

Because size does not change in the case of the stream, the map can be skipped entirely, since all we do is counting.

You can create a Spliterator around an Iterator if you need to, via:

Spliterators.spliteratorUnknownSize(yourIterator, properties)
Wednesday, July 28, 2021
 
TheFrack
answered 5 Months ago
89

Task implements Runnable, so when you call handler.run(); you actually run the call method in the UI Thread. That will hang the UI.

You should start the task in a background thread, either via an executor or simply by calling new Thread(handler).start();.

This is explained (maybe not very clearly) in the javadoc or in the JavaFX concurrency tutorial.

Wednesday, July 28, 2021
 
kwichz
answered 5 Months ago
38

Your question is somewhat confusing, it's like asking: Do I buy apples or tomatoes? The answer is, it really depends on what you want to do, since they're completely different.

Essentially, you have answered your own question to some extent, because you already know the differences between the two:

  • this refers to the current context
  • self refers to window
function myAPI() {
     this.auth = auth;
     this.nodeAPI = nodeAPI;
     return this;
    }
module.exports = myAPI;

You're asking whether you can use self instead. Think about it, what does this allow you to do? It allows you, to refer to the context. What is the context, well, it's module when you call module.exports(). And module is most likely not going to be window, so no, you can't use self here.

Does that answer the question?

The second code example seems to do something completely different. I don't know what to make of that.

Sunday, August 22, 2021
 
Jame
answered 4 Months ago
22

If you find locking on the object itself too heavy, then synchronized is the way to go. Prior to Java 1.5 volatile may have been a good choice, but now volatile can have a very large impact by forcing instruction ordering on the method where the assignment happens. Create a separate object (private final Object X_LOCK = new Object();) and synchronize on it when setting or getting the value of that double. This will give you a fine level of control over the locking, which it seems that you need.

In the new concurrency package there are more options, such as AtomicReference which may be a good replacement for volatile if you really need to avoid synchronization.

Sunday, September 12, 2021
 
Gili
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share