15

What are the possible ways to make code thread-safe without using the synchronized keyword?

5
  • 2
    why close ? Its a good succinct question Commented Apr 26, 2012 at 9:55
  • @NimChimpsky I don't know either, the question seems perfectly valid to me. It is definitely answerable, and the answers are not something subjective. Commented Apr 26, 2012 at 10:00
  • @NimChimpsky "Too broad" I presume. Commented Aug 3, 2018 at 11:31
  • To add to discussion I just posted a lengthy epilogue here Thread synchronization without locks Commented Jun 25, 2021 at 10:19
  • I just posted the answer here. Synchronization without locks Commented Jun 25, 2021 at 10:20

7 Answers 7

11

Actually, lots of ways:

  1. No need for synchronization at all if you don't have mutable state.
  2. No need for synchronization if the mutable state is confined to a single thread. This can be done by using local variables or java.lang.ThreadLocal.
  3. You can also use built-in synchronizers. java.util.concurrent.locks.ReentrantLock has the same functionality as the lock you access when using synchronized blocks and methods, and it is even more powerful.
Sign up to request clarification or add additional context in comments.

4 Comments

I prefer (2), but I'm not sure if its' possible to implement message-passing without using the 'synchronized' keyword. Can I make a producer-consumer queue without 'synchronized'?
@MartinJames Any of the Concurrent classes like Queues and Exchangers can be used without synchronization. (They use Lock instead) The Disrupter supports messaging without locks or synchronization. (I have a library which does this as well)
@PeterLawrey - so, thread-safe code without the 'synchronized' keyword is certainly possible and, in fact practical. Now, all that remains is to get developers to stop using Thread.join() and we're done :)
@MartinJames It is better to say that thread-safe code is possible without locking. Sometimes you can avoid using locking completely (intrinsic locks or not, doesn't matter), and then everything becomes much easier. However, if you get to locking, it is better to use synchronized than extrinsic locks if you don't need advanced features. The notaion of intrinsic locks is concise, and the code doesn't need to contain try-finally blocks (therefore much safer).
6

Only have variables/references local to methods. Or ensure that any instance variables are immutable.

Comments

4

You can make your code thread-safe by making all the data immutable, if there is no mutability, everything is thread-safe.

Secondly, you may want to have a look at java concurrent API which has provision for providing read / write locks which perform better in case there are lots of readers and a few writers. Pure synchronized keyword will block two readers also.

Comments

4
 ////////////FIRST METHOD USING SINGLE boolean////////////// public class ThreadTest implements Runnable { ThreadTest() { Log.i("Ayaz", "Constructor.."); } private boolean lockBoolean = false; public void run() { Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName()); while (lockBoolean) { // infinite loop for other thread if one is accessing } lockBoolean = true; synchronizedMethod(); } /** * This method is synchronized without using synchronized keyword */ public void synchronizedMethod() { Log.e("Ayaz", "processing...." + Thread.currentThread().getName()); try { Thread.currentThread().sleep(3000); } catch (Exception e) { System.out.println("Exp"); } Log.e("Ayaz", "complete.." + Thread.currentThread().getName()); lockBoolean = false; } } //end of ThreadTest class //For testing use below line in main method or in Activity ThreadTest threadTest = new ThreadTest(); Thread threadA = new Thread(threadTest, "A thead"); Thread threadB = new Thread(threadTest, "B thead"); threadA.start(); threadB.start(); ///////////SECOND METHOD USING TWO boolean///////////////// public class ThreadTest implements Runnable { ThreadTest() { Log.i("Ayaz", "Constructor.."); } private boolean isAnyThreadInUse = false; private boolean lockBoolean = false; public void run() { Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName()); while (!lockBoolean) if (!isAnyThreadInUse) { isAnyThreadInUse = true; synchronizedMethod(); lockBoolean = true; } } /** * This method is synchronized without using synchronized keyword */ public void synchronizedMethod() { Log.e("Ayaz", "processing...." + Thread.currentThread().getName()); try { Thread.currentThread().sleep(3000); } catch (Exception e) { System.out.println("Exp"); } Log.e("Ayaz", "complete.." + Thread.currentThread().getName()); isAnyThreadInUse = false; } } // end of ThreadTest class //For testing use below line in main method or in Activity ThreadTest threadTest = new ThreadTest(); Thread t1 = new Thread(threadTest, "a thead"); Thread t2 = new Thread(threadTest, "b thead"); t1.start(); t2.start(); 

Comments

2

To maintain predictability you must either ensure all access to mutable data is made sequentially or handle the issues caused by parallel access.

The most gross protection uses the synchronized keyword. Beyond that there are at least two layers of possibility, each with their benefits.

Locks/Semaphores

These can be very effective. For example, if you have a structure that is read by many threads but only updated by one you may find a ReadWriteLock useful.

Locks can be much more efficient if you choose your lock to match the algorithm.

Atomics

Use of AtomicReference for example can often provide completely lock free functionality. This can usually provide huge benefits.

The reasoning behind atomics is to allow them to fail but to tell you they failed in a way you can handle it.

For example, if you want to change a value you can read it and then write its new value so long as it is still the old value. This is called a "compare and set" or cas and can usually be implemented in hardware and so is extremely efficient. All you then need is something like:

long old = atomic.get(); while ( !atomic.cas(old, old+1) ) { // The value changed between my get and the cas. Get it again. old = atomic.get(); } 

Note, however, that predictability is not always the requirement.

Comments

0

Well there are many ways you can achieve this, but each contains many flavors. Java 8 also ships with new concurrency features. Some ways you could make sure thread safety are:
Semaphores
Locks-Reentrantlock,ReadWriteLock,StampedLock(Java 8)

Comments

-2

Why do u need to do it?

Using only local variable/references will not solve most of the complex business needs. Also, if instance variable are immutable, their references can still be changed by other threads.

One option is use something like a SingleThreadModel, but it is highly discouraged and deprecated.

u can also look at concurrent api as suggested above by Kal

10 Comments

"if instance variable are immutable, their references can still be changed" no they can't
can u explain that. How i see it is if i have a instanace variable String s ="xyz", My thread1 can change the reference of it to s="abc"; and thread2 will now get s="abc"
s is a reference, it has changed, its not immutable you would need "final string s"
with string s your s reference is not immutable it can reference a different string, just by doing s = "yourarewrong". You say immutable instance variables are not thread safe, and then give an example of a mutable instance variable.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.