Java: Do all static methods need to be synchronized? - java

I have a friend who said that all static methods should be synchronized in the context of a Java web application. Is that true? I have read many other stack overflow pages regarding this. What I have come to believe is that you only need to synchronize if you have:
Multiple Threads (As in a Sevlet Container with a thread pool)
Single ClassLoader
Shared data between threads, whether it is Session data or static member data.
Shared data must be mutable. Read only data is ok to share.
Based on this I think that static members should be synchronized, but not static methods.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
static String staticString = "";
// This static method is safe b/c it only uses local data.
// It does not use any shared mutable data.
// It even uses a string builder.
static String safeStaticMethod(String in) {
// This also proves that StringBuilder is safe
// When used locally by a thread.
StringBuilder sb = new StringBuilder();
sb.append("Hello: ");
sb.append(in);
return sb.toString();
}
// This static method is not safe b/c it updates and reads
// shared mutable data among threads.
// Adding synchronized will make this safe.
static String unsafeStaticMethod(String in) {
staticString = in;
StringBuffer sb = new StringBuffer();
sb.append("Hello: ");
sb.append(staticString);
return sb.toString();
}
public static void main(String[] args) {
ThreadTest test = new ThreadTest();
test.staticMethodWithLocalData();
test.staticMethodWithStaticData();
}
public void staticMethodWithLocalData() {
ExecutorService executor = Executors.newFixedThreadPool(2);
final int iterations = 100000;
executor.submit(new Runnable() {
#Override
public void run() {
for (int index = 0; index < iterations; ++index) {
if (!safeStaticMethod("Thread1").equals("Hello: Thread1")) {
System.out.println("safeStaticMethod at " + index);
}
}
}
});
executor.submit(new Runnable() {
#Override
public void run() {
for (int index = 0; index < iterations; ++index) {
if (!safeStaticMethod("Thread2").equals("Hello: Thread2")) {
System.out.println("safeStaticMethod at " + index);
}
}
}
});
}
public void staticMethodWithStaticData() {
ExecutorService executor = Executors.newFixedThreadPool(2);
final int iterations = 100000;
executor.submit(new Runnable() {
#Override
public void run() {
for (int index = 0; index < iterations; ++index) {
if (!unsafeStaticMethod("Thread1").equals("Hello: Thread1")) {
System.out.println("unsafeStaticMethod at " + index);
}
}
}
});
executor.submit(new Runnable() {
#Override
public void run() {
for (int index = 0; index < iterations; ++index) {
if (!unsafeStaticMethod("Thread2").equals("Hello: Thread2")) {
System.out.println("unsafeStaticMethod at " + index);
}
}
}
});
}
}
Does this code prove the point?
EDIT: This is only some throwaway code I hacked up to prove the point.

No, not all static methods need to be synchronized. Your list is basically complete as far as I can see. Be particularly careful when the static method either
accesses a static member that is mutable, or
gets passed a reference to an object that can be modified.
I think it goes without saying that 1 (having threads in the first place) is a precondition, since without threads synchronize makes no sense.
I've never heard 2, so I don't know for sure if it's a consideration.

No that's not true and I'm sure it would be detrimental. Not every application needs to be concurrent, and even in applications that do need to be concurrent, not every piece of code has to be.
As more evidence, look at the source of String. There are many static methods in there, but I could only find one synchronized method, and that one isn't even static.

Static methods should almost never be synchronized in a webapp. Unless you are 100% sure that the only people who will ever use the application are your 3 person accounting team, and willing to be red in the face if it takes off company-wide and all of the sudden grinds to a near halt.
Creating a global, blocking, shared resource is a total failure in scalability! It's also going to cause you lots of headaches and likely lock you into a Terracotta style solution if you end up needing to cluster the application server.

In a web application(like one build using the servlet/JSP), you should always avoid making a method as synchronized as it challenges the whole philosophy of mutli-thread accessibility. In place, always try to place the only necessary code, which needs to be accessed one by one, inside the synchronized block.

Not at all. Mostly, the static methods that I have come across do not modify any static variables and hence they do not require to be synchronized.
For simple understanding,
//sample static util method to get string in upper case
public static String getName(String name){
return a.toUpperCase();
}
The above method can be called by 1000s of threads and yet it is going to be thread-safe because the method only requires an argument- String name and that is from the Thread Stack. It is not shared data between threads.
Think about it, if all the static methods were synchonized, the web-applications shall be extremely slow and lethargic to use. We shall have class-level lock whenever a single thread tries to access the method.
There are a lot of static methods in the APIs provided by JDK. If all those were synchronized, am pretty sure we wouldn't be using JAVA.
In your case, there is a static variable(class level variable) that is being modified by the static method. Yes, if multiple threads are created and they are going to access the static method, there is a possibility of Thread Interference. It is not thread-safe as there is shared data between them.
Mostly, the static methods are utility functions depending on the arguments being passed to them.
Please note that non-synchronized static methods are thread safe if they don't modify static class variables.

Related

Why a synchronized getter work like a volatile read?

This program does not terminate!
public class Main extends Thread {
private int i = 0;
private int getI() {return i; }
private void setI(int j) {i = j; }
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.start();
Thread.sleep(1000);
main.setI(10);
}
public void run() {
System.out.println("Awaiting...");
while (getI() == 0) ;
System.out.println("Done!");
}
}
I understand this happens because the CPU core running the Awaiting loop always sees the cached copy of i and misses the update.
I also understand that if I make volatileprivate int i = 0; then the while (getI()... will behave[1] as if every time it is consulting the main memory - so it will see the updated value and my program will terminate.
My question is: If I make
synchronized private int getI() {return i; }
It surprisingly works!! The program terminates.
I understand that synchronized is used in preventing two different threads from simultaneously entering a method - but here is only one thread that ever enters getI(). So what sorcery is this?
Edit 1
This (synchronization) guarantees that changes to the state of the object are visible to all threads
So rather than directly having the private state field i, I made following changes:
In place of private int i = 0; I did private Data data = new Data();, i = j changed to data.i = j and return i changed to return data.i
Now the getI and setI methods are not doing anything to the state of the object in which they are defined (and may be synchronized). Even now using the synchronized keyword is causing the program to terminate! The fun is in knowing that the object whose state is actually changing (Data) has no synchronization or anything built into it. Then why?
[1] It will probably just behave as that, what actually, really happens is unclear to me
It is just coincidence or platform dependent or specific JVM dependent, it is not guaranteed by JLS. So, do not depend on it.

How to solve race condition of two writers using immutable objects

I was thinking about how to solve race condition between two threads which tries to write to the same variable using immutable objects and without helping any keywords such as synchronize(lock)/volatile in java.
But I couldn't figure it out, is it possible to solve this problem with such solution at all?
public class Test {
private static IAmSoImmutable iAmSoImmutable;
private static final Runnable increment1000Times = () -> {
for (int i = 0; i < 1000; i++) {
iAmSoImmutable.increment();
}
};
public static void main(String... args) throws Exception {
for (int i = 0; i < 10; i++) {
iAmSoImmutable = new IAmSoImmutable(0);
Thread t1 = new Thread(increment1000Times);
Thread t2 = new Thread(increment1000Times);
t1.start();
t2.start();
t1.join();
t2.join();
// Prints a different result every time -- why? :
System.out.println(iAmSoImmutable.value);
}
}
public static class IAmSoImmutable {
private int value;
public IAmSoImmutable(int value) {
this.value = value;
}
public IAmSoImmutable increment() {
return new IAmSoImmutable(++value);
}
}
If you run this code you'll get different answers every time, which mean a race condition is happening.
You can not solve race condition without using any of existence synchronisation (or volatile) techniques. That what they were designed for. If it would be possible there would be no need of them.
More particularly your code seems to be broken. This method:
public IAmSoImmutable increment() {
return new IAmSoImmutable(++value);
}
is nonsense for two reasons:
1) It makes broken immutability of class, because it changes object's variable value.
2) Its result - new instance of class IAmSoImmutable - is never used.
The fundamental problem here is that you've misunderstood what "immutability" means.
"Immutability" means — no writes. Values are created, but are never modified.
Immutability ensures that there are no race conditions, because race conditions are always caused by writes: either two threads performing writes that aren't consistent with each other, or one thread performing writes and another thread performing reads that give inconsistent results, or similar.
(Caveat: even an immutable object is effectively mutable during construction — Java creates the object, then populates its fields — so in addition to being immutable in general, you need to use the final keyword appropriately and take care with what you do in the constructor. But, those are minor details.)
With that understanding, we can go back to your initial sentence:
I was thinking about how to solve race condition between two threads which tries to write to the same variable using immutable objects and without helping any keywords such as synchronize(lock)/volatile in java.
The problem here is that you actually aren't using immutable objects: your entire goal is to perform writes, and the entire concept of immutability is that no writes happen. These are not compatible.
That said, immutability certainly has its place. You can have immutable IAmSoImmutable objects, with the only writes being that you swap these objects out for each other. That helps simplify the problem, by reducing the scope of writes that you have to worry about: there's only one kind of write. But even that one kind of write will require synchronization.
The best approach here is probably to use an AtomicReference<IAmSoImmutable>. This provides a non-blocking way to swap out your IAmSoImmutable-s, while guaranteeing that no write gets silently dropped.
(In fact, in the special case that your value is just an integer, the JDK provides AtomicInteger that handles the necessary compare-and-swap loops and so on for threadsafe incrementation.)
Even if the problems are resolved by :
Avoiding the change of IAmSoImmutable.value
Reassigning the new object created within increment() back into the iAmSoImmutable reference.
There still are pieces of your code that are not atomic and that needs a sort of synchronization.
A solution would be to use a synchronized method of course
public synchronized static void increment() {
iAmSoImmutable = iAmSoImmutable.increment();
}
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});

Read and write from global variables

What I'm trying to do is have a global variable classes and function can read/write from/to.
What I have now is
import java.lang.*;
import lab1.Global;
public class SecondProgram {
public static void main ( String args[] ) {
System.out.println("hi ");
Global.b[0] = " zero ";
Global.b[1] = " One ";
Global.b[2] = " Two ";
Global.b[3] = " Three ";
}
}
and I created a class to store the global variables
public class Global {
public static String a = "hi" ;
public static String [] b;
}
Of course it is important that the size of the array isn't a hardcoded constant but a variable I'll be able to find out at some point and plug in.
I hope you can see from the code what I'm trying to do, and you know how to make it work.
Thanks!
I want global variables because i am having threads read data from text files into arrays, and it's important that the arrays and their data stay present after the thread finishes its work.
Well that won't work. Or at least, it won't work reliably (and in a sense that is a worse outcome!)
In a multi-threaded Java program, you need to be sure that the threads synchronize properly at points where information gets passed from one to another. The purpose of the synchronization is twofold:
to prevent race conditions; i.e. where one thread tries to read a value before another one has read it, and
to ensure that threads don't see stale copies of values due to memory caching effects.
Synchronizing bare global variables is going to be fiendishly hard. My advice is
Pay attention to the comments (above) and design and implement using classes to encapsulate the state.
Use the utility classes in java.util.concurrent to implement the shared data structures ... and handle thread creation / management. Look at the ExecutorService API for example,
Get a good textbook on concurrent programming in Java. Concurrency in Java is not simple, and if you don't know what you are doing you can spend hours / days / weeks / months tracking down the causes of intermittent failures.
i think this is a far better approach and something to get you started....
import java.util.ArrayList;
public class SecondProgram {
private static ArrayList <String>file = new ArrayList();
public synchronized boolean writeFile(String str){
//wrtite file to your list
file.add(str);
return true;
}
public static void main(String args[]) {
//read file and use the synchronized method to write it to your list
}
}
I don't advocate the use of globals, but if you must, you can do something like the following. In general: have each thread build up its own data. When it is finished doing its work, add its data to a synchronized global collection (in this case, a List<List<String>>). Then read that collection once all of the threads have finished their work.
The global that collects the data:
public class GlobalDataBroker {
public static List<List<String>> data = Collections.synchronizedList(new LinkedList<List<String>>());
}
An example implementation:
public static void main(String[] args) throws InterruptedException {
for (int i=0; i < 10; i++) {
new Thread(new Runnable(){
#Override
public void run() {
List<String> list = new LinkedList<String>();
list.add(String.format("I'm a Thread and my name is %s.",Thread.currentThread()));
for (int i = 0; i < 5; i++) {
list.add("Data!");
}
GlobalDataBroker.data.add(list);
}
}).start();
}
// When the threads are done ...
Iterator<List<String>> i = GlobalDataBroker.data.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
}
Output:
[I'm a Thread and my name is Thread[Thread-8,5,main]., Data!, Data!, Data!, Data!, Data!]
[I'm a Thread and my name is Thread[Thread-5,5,main]., Data!, Data!, Data!, Data!, Data!]
...
[I'm a Thread and my name is Thread[Thread-7,5,main]., Data!, Data!, Data!, Data!, Data!]
Note that you should only begin iterating over your data once you've completed writing it. (Otherwise, you may encounter the dreaded ConcurrentModificationException.)

The code example which can prove "volatile" declare should be used

Currently I can't understand when we should use volatile to declare variable.
I have do some study and searched some materials about it for a long time and know that when a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations.
However, I still can't understand in what scenario we should use it. I mean can someone provide any example code which can prove that using "volatile" brings benefit or solve problems compare to without using it?
Here is an example of why volatile is necessary. If you remove the keyword volatile, thread 1 may never terminate. (When I tested on Java 1.6 Hotspot on Linux, this was indeed the case - your results may vary as the JVM is not obliged to do any caching of variables not marked volatile.)
public class ThreadTest {
volatile boolean running = true;
public void test() {
new Thread(new Runnable() {
public void run() {
int counter = 0;
while (running) {
counter++;
}
System.out.println("Thread 1 finished. Counted up to " + counter);
}
}).start();
new Thread(new Runnable() {
public void run() {
// Sleep for a bit so that thread 1 has a chance to start
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
// catch block
}
System.out.println("Thread 2 finishing");
running = false;
}
}).start();
}
public static void main(String[] args) {
new ThreadTest().test();
}
}
The following is a canonical example of the necessity of volatile (in this case for the str variable. Without it, hotspot lifts the access outside the loop (while (str == null)) and run() never terminates. This will happen on most -server JVMs.
public class DelayWrite implements Runnable {
private String str;
void setStr(String str) {this.str = str;}
public void run() {
  while (str == null);
  System.out.println(str);
}
public static void main(String[] args) {
  DelayWrite delay = new DelayWrite();
  new Thread(delay).start();
  Thread.sleep(1000);
  delay.setStr("Hello world!!");
}
}
Eric, I have read your comments and one in particular strikes me
In fact, I can understand the usage of volatile on the concept
level. But for practice, I can't think
up the code which has concurrency
problems without using volatile
The obvious problem you can have are compiler reorderings, for example the more famous hoisting as mentioned by Simon Nickerson. But let's assume that there will be no reorderings, that comment can be a valid one.
Another issue that volatile resolves are with 64 bit variables (long, double). If you write to a long or a double, it is treated as two separate 32 bit stores. What can happen with a concurrent write is the high 32 of one thread gets written to high 32 bits of the register while another thread writes the low 32 bit. You can then have a long that is neither one or the other.
Also, if you look at the memory section of the JLS you will observe it to be a relaxed memory model.
That means writes may not become visible (can be sitting in a store buffer) for a while. This can lead to stale reads. Now you may say that seems unlikely, and it is, but your program is incorrect and has potential to fail.
If you have an int that you are incrementing for the lifetime of an application and you know (or at least think) the int wont overflow then you don't upgrade it to a long, but it is still possible it can. In the case of a memory visibility issue, if you think it shouldn't effect you, you should know that it still can and can cause errors in your concurrent application that are extremely difficult to identify. Correctness is the reason to use volatile.
The volatile keyword is pretty complex and you need to understand what it does and does not do well before you use it. I recommend reading this language specification section which explains it very well.
They highlight this example:
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
What this means is that during one() j is never greater than i. However, another Thread running two() might print out a value of j that is much larger than i because let's say two() is running and fetches the value of i. Then one() runs 1000 times. Then the Thread running two finally gets scheduled again and picks up j which is now much larger than the value of i. I think this example perfectly demonstrates the difference between volatile and synchronized - the updates to i and j are volatile which means that the order that they happen in is consistent with the source code. However the two updates happen separately and not atomically so callers may see values that look (to that caller) to be inconsistent.
In a nutshell: Be very careful with volatile!
A minimalist example in java 8, if you remove volatile keyword it will never end.
public class VolatileExample {
private static volatile boolean BOOL = true;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> { while (BOOL) { } }).start();
TimeUnit.MILLISECONDS.sleep(500);
BOOL = false;
}
}
To expand on the answer from #jed-wesley-smith, if you drop this into a new project, take out the volatile keyword from the iterationCount, and run it, it will never stop. Adding the volatile keyword to either str or iterationCount would cause the code to end successfully. I've also noticed that the sleep can't be smaller than 5, using Java 8, but perhaps your mileage may vary with other JVMs / Java versions.
public static class DelayWrite implements Runnable
{
private String str;
public volatile int iterationCount = 0;
void setStr(String str)
{
this.str = str;
}
public void run()
{
while (str == null)
{
iterationCount++;
}
System.out.println(str + " after " + iterationCount + " iterations.");
}
}
public static void main(String[] args) throws InterruptedException
{
System.out.println("This should print 'Hello world!' and exit if str or iterationCount is volatile.");
DelayWrite delay = new DelayWrite();
new Thread(delay).start();
Thread.sleep(5);
System.out.println("Thread sleep gave the thread " + delay.iterationCount + " iterations.");
delay.setStr("Hello world!!");
}

Data race in Java ArrayList class

I was reading about CopyOnWriteArrayList and was wondering how can I demonstrate data race in ArrayList class. Basically I'm trying to simulate a situation where ArrayList fails so that it becomes necessary to use CopyOnWriteArrayList. Any suggestions on how to simulate this.
A race is when two (or more) threads try to operate on shared data, and the final output depends on the order the data is accessed (and that order is indeterministic)
From Wikipedia:
A race condition or race hazard is a flaw in an electronic system or process whereby the output and/or result of the process is unexpectedly and critically dependent on the sequence or timing of other events. The term originates with the idea of two signals racing each other to influence the output first.
For example:
public class Test {
private static List<String> list = new CopyOnWriteArrayList<String>();
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(5);
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.awaitTermination(20, TimeUnit.SECONDS);
}
static class WriterTask implements Runnable {
#Override
public void run() {
for (int i = 0; i < 25000; i ++) {
list.add("a");
}
}
}
}
This, however, fails when using ArrayList, with ArrayIndexOutOfbounds. That's because before insertion the ensureCapacity(..) should be called to make sure the internal array can hold the new data. And here's what happens:
the first thread calls add(..), which in turn calls ensureCapacity(currentSize + 1)
before the first thread has actually incremented the size, the 2nd thread also calls ensureCapacity(currentSize + 1).
because both have read the initial value of currentSize, the new size of the internal array is currentSize + 1
the two threads make the expensive operation to copy the old array into the extended one, with the new size (which cannot hold both additions)
Then each of them tries to assign the new element to array[size++]. The first one succeeds, the second one fails, because the internal array has not been expanded properly, due to the rece condition.
This happens, because two threads have tried to add items at the same time on the same structure, and the addition of one of them has overridden the addition of the other (i.e. the first one was lost)
Another benefit of CopyOnWriteArrayList
multiple threads write to the ArrayList
a thread iterates the ArrayList. It will surely get ConcurrentModificationException
Here's how to demonstrate it:
public class Test {
private static List<String> list = new ArrayList<String>();
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(2);
e.execute(new WriterTask());
e.execute(new ReaderTask());
}
static class ReaderTask implements Runnable {
#Override
public void run() {
while (true) {
for (String s : list) {
System.out.println(s);
}
}
}
}
static class WriterTask implements Runnable {
#Override
public void run() {
while(true) {
list.add("a");
}
}
}
}
If you run this program multiple times, you will often be getting ConcurrentModificationException before you get OutOfMemoryError.
If you replace it with CopyOnWriteArrayList, you don't get the exception (but the program is very slow)
Note that this is just a demonstration - the benefit of CopyOnWriteArrayList is when the number of reads vastly outnumbers the number of writes.
Example:
for (int i = 0; i < array.size(); ++i) {
Element elm = array.get(i);
doSomethingWith(elm);
}
If another thread calls array.clear() before this thread calls array.get(i), but after it has compared i with array.size(), -> ArrayIndexOutOfBoundsException.
Two threads, one incrementing the arraylist and one decrementing. Data race could happen here.

Categories