Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this class not thread safe?

class ThreadSafeClass extends Thread
{
     private static int count = 0;

     public synchronized static void increment()
     {
         count++;
     }

     public synchronized void decrement()
     {
         count--;
     }
}

Can anyone explain why above class is not thread safe?

like image 530
das kinder Avatar asked May 13 '15 07:05

das kinder


People also ask

Which class is not a thread-safe?

When designing a class that may be used for concurrent programming—that is, a class whose instances may be used by more than one thread at a time—it is imperative that you make sure the class is " thread-safe.” Consider the IntList class of Example 2-7. This class is not thread safe.

How do you know if a class is thread-safe?

For a standard Java SE class, the best way to know whether or not the class is thread-safe is to carefully read its documentation. Always read both the class documentation and the method documentation. If either say it's not synchronized or not thread-safe, you know it's not thread-safe.

What does it mean not thread-safe?

Not thread safe: Data structures should not be accessed simultaneously by different threads.

What is not thread-safe in Java?

When multiple threads are working on the same data, and the value of our data is changing, that scenario is not thread-safe and we will get inconsistent results. When a thread is already working on an object and preventing another thread on working on the same object, this process is called Thread-Safety.

What is a thread-safe class?

Thread-Safe Classes - Java Examples in a Nutshell, 3rd Edition [Book] When designing a class that may be used for concurrent programming—that is, a class whose instances may be used by more than one thread at a time—it is imperative that you make sure the class is " thread-safe.” Consider the IntList class of Example 2-7.

How do you make a class Thread safe in Java?

To make these classes thread-safe, you must prevent concurrent access to the internal state of an instance by more than one thread. Because Java was designed with threads in mind, the language provides the synchronized modifier, which does just that.

Is multithreading in Java thread-safe?

As we know Java has a feature, Multithreading, which is a process of running multiple threads simultaneously. When multiple threads are working on the same data, and the value of our data is changing, that scenario is not thread-safe and we will get inconsistent results.

What is thread safety and why is it important?

Although multithreading is a powerful feature, it comes at a price. In multithreaded environments, we need to write implementations in a thread-safe way. This means that different threads can access the same resources without exposing erroneous behavior or producing unpredictable results. This programming methodology is known as “thread-safety”.


7 Answers

Since the increment method is static it will synchronize on the class object for the ThreadSafeClass. The decrement method is not static and will synchronize on the instance used to call it. I.e., they will synchronize on different objects and thus two different threads can execute the methods at the same time. Since the ++ and -- operations are not atomic the class is not thread safe.

Also, since count is static, modifying it from decrement which is a synchronized instance method is unsafe since it can be called on different instances and modify count concurrently that way.

like image 104
K Erlandsson Avatar answered Oct 20 '22 23:10

K Erlandsson


You have two synchronized methods, but one of them is static and the other is not. When accessing a synchronized method, based on it's type (static or non-static), a different object will be locked. For a static method, a lock will be put on the Class object, while for the non-static block, a lock will be put on the instance of the class that runs the method. Because you have two different locked objects, you can have two threads that modify the same object simultaneously.

like image 40
Slimu Avatar answered Oct 20 '22 23:10

Slimu


Can anyone explain why above class is not thread safe?

  • increment being static, synchronization will be done on the class itself.
  • decrement being not static, synchronization will be done on the object instantiation, but that doesn't secure anything as count is static.

I'd like to add that to declare a thread-safe counter, I believe the simplest way is to use AtomicInteger instead of a primitive int.

Let me redirect you to the java.util.concurrent.atomic package-info.

like image 38
Jean-François Savard Avatar answered Oct 21 '22 01:10

Jean-François Savard


Others' answers are pretty good explained the reason. I just add something to summarize synchronized:

public class A {
    public synchronized void fun1() {}

    public synchronized void fun2() {}

    public void fun3() {}

    public static synchronized void fun4() {}

    public static void fun5() {}
}

A a1 = new A();

synchronized on fun1 and fun2 is synchronized on instance object level. synchronized on fun4 is synchronized on class object level. Which means:

  1. When 2 threads call a1.fun1() at same time, latter call will be blocked.
  2. When thread 1 call a1.fun1() and thread 2 call a1.fun2() at same time, latter call will be blocked.
  3. When thread 1 call a1.fun1() and thread 2 call a1.fun3() at same time, no blocking, the 2 methods will be executed at same time.
  4. When thread 1 call A.fun4(), if other threads call A.fun4() or A.fun5() at same time, latter calls will be blocked since synchronized on fun4 is class level.
  5. When thread 1 call A.fun4(), thread 2 call a1.fun1() at same time, no blocking, the 2 methods will be executed at same time.
like image 25
coderz Avatar answered Oct 21 '22 01:10

coderz


  1. decrement is locking on a different thing to increment so they do not prevent each other from running.
  2. Calling decrement on one instance is locking on a different thing to calling decrement on another instance, but they are affecting the same thing.

The first means that overlapping calls to increment and decrement could result in a cancel-out (correct), an increment or a decrement.

The second means that two overlapping calls to decrement on different instances could result in a double decrement (correct) or a single decrement.

like image 6
Jon Hanna Avatar answered Oct 21 '22 01:10

Jon Hanna


Since two different methods, one is instance level and other is class level, so you need to lock on 2 different objects to make it ThreadSafe

like image 4
jaleel_quest Avatar answered Oct 21 '22 00:10

jaleel_quest


As explained in other answers, your code is not Thread safe since static method increment() locks Class monitor and non-static method decrement() locks Object monitor.

For this code example, better solution exists without synchronzed keyword usage. You have to use AtomicInteger to achieve Thread safety.

Thread safe using AtomicInteger:

import java.util.concurrent.atomic.AtomicInteger;

class ThreadSafeClass extends Thread {

    private static AtomicInteger count = new AtomicInteger(0);

    public static void increment() {
        count.incrementAndGet();
    }

    public static void decrement() {
        count.decrementAndGet();
    }

    public static int value() {
        return count.get();
    }

}
like image 1
Ravindra babu Avatar answered Oct 21 '22 00:10

Ravindra babu