0

I tried the thread race program with Synchronization,lock.lock() and lock.tryLock(),I found that with synchronization and lock.lock() works fine,but lock.tryLock() itself is not thread safe.This method is not able to acquire the lock and hence giving unexpected results


import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 10; i++) {


            Resources resources = new Resources();
            Thread userThread1 = new Increment(resources);
            Thread userThread2 = new Decrement(resources);
            userThread1.start();
            userThread2.start();
            userThread1.join();
            userThread2.join();

            System.out.println(resources.getCounter());
        }
    }

    private static abstract class UserThread extends Thread {
        protected Resources resources;

        public UserThread(Resources resources) {
            this.resources = resources;
        }

    }

    private static class Increment extends UserThread {

        public Increment(Resources resources) {
            super(resources);
        }

        public void run() {
            for (int i = 0; i < 10000; i++) {
                resources.increemnt();

            }

        }
    }

    private static class Decrement extends UserThread {

        public Decrement(Resources resources) {
            super(resources);
        }

        public void run() {

            for (int i = 0; i < 10000; i++) {
                resources.decrement();

            }

        }
    }

    private static class Resources {

        public ReentrantLock getLock() {
            return lock;
        }

        private ReentrantLock lock = new ReentrantLock();

        public int getCounter() {
            return counter;
        }

        private int counter = 0;

        public void increemnt() {
            if (lock.tryLock()) {
                try {
                    counter++;
                } finally {
                    lock.unlock();
                }

            }
        }

        public void decrement() {
            if (lock.tryLock()) {
                try {
                    counter--;
                } finally {
                    lock.unlock();
                }

            }
        }
    }

}

Expected: 0,0,0,0,0,0,0,0,0,0 Actual output: its random for every run

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
Sriharsha g.r.v
  • 456
  • 5
  • 13

1 Answers1

2

The tryLock method is thread-safe. It does what it is supposed to do (according to the javadoc) reliably.

However, the way that you are using the trylock results in a non-thread-safe implementation of increment and decrement. If you are going to use trylock in that situation, you will need to do something like this:

try {
    while (!lock.tryLock()) { }  // Try to get the lock until you get it
    counter++;
} finally {
    lock.unlock();
}

But that is a bad idea because you are effectively busy-waiting on the lock. A better solution using a Lock would be:

try {
    lock.lock();  // Block until the lock is acquired.
    counter++;
} finally {
    lock.unlock();
}

But if you are after a lock-free solution, then you should be using an atomic type:

  • java.util.concurrent.atomic.LongAdder (javadoc) for Java 8 and later,
  • java.util.concurrent.atomic.AtomicLong (javadoc) all versions of Java since Java 5 inclusive.

Apparently LongAdder performs better if there is a lot of contention:


Note that thread-safety is actually a difficult concept to define precisely. You need to start from a behavioral specification of the correct behavior of an algorithm. Then you can say that an implementation of the algorithm.

Definition: When the algorithm is correct according to the specification when run on system with one processor, then it is thread-safe if it is also always correct according to the specification when there are multiple processors.

From this, we see that:

  • thread-safety is moot if the algorithm doesn't meet its behavioral specification in the single processor case, and
  • thread-safety is moot if the algorithm cannot use multiple processors.
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216