Reentrant lock releases automatically in java - java

Is there any way can we release the re entrant lock automatically.does not need to unlock in finally block is there any way to achieve this
try{
lock.lock;
}
catch(Exception e){
lock.unlock
}

It can be done with an annotation but using the AutoCloseable is also an option:
import java.util.concurrent.locks.ReentrantLock;
public class LockTry {
public static void main(String[] args) {
new LockTry().testWithLock();
}
private void testWithLock() {
ReentrantLock lock = new ReentrantLock();
try (CloseableLock clock = new CloseableLock(lock)) {
System.out.println("run with lock");
}
}
static class CloseableLock implements AutoCloseable {
private final ReentrantLock lock;
CloseableLock(ReentrantLock lock) {
super();
this.lock = lock;
lock.lock();
System.out.println("locked");
}
#Override
public void close() {
lock.unlock();
System.out.println("unlocked");
}
}
}

Related

Java: why doesn't deadlock happen when in this simple example with two threads

I have this code:
public class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
...
public synchronized byte[] read(int address) {...}
public synchronized boolean write(byte[] data, int address) {...}
public synchronized void erase(int address) {...}
...
I'm trying to simulate a deadlock
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
#Override
public void run() {
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
#Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
However deadlock doesn't happen - why? ThreadA calls method cutAndPaste() locked on usb1, while inside that method write() is called which is locked on usb2
Shouldn't deadlock occur?
How should I change the code to trigger deadlock?
I get this output:
reading data
Erasing data
reading data
Erasing data
It is a race condition that decides whether the deadlock happens or not as far as I can see, one good option to make the deadlock more likely to happen is a loop, but an easier option might be to insert Thread.sleep(5000); between byte[] data = read(originAddress); and boolean success = other.write(data, destAddress); in UsbDrive::cutAndPaste. EDIT: And remove the existing Thread.sleep(5000);.
EDIT: Clarified answer.
EDIT2: I just ran the code with the changes, and it indeed induces a deadlock now:
import java.util.Date;
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
#Override
public void run() {
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
#Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
public synchronized byte[] read(int address) {return new byte[]{};}
public synchronized boolean write(byte[] data, int address) {return true;}
public synchronized void erase(int address) {}
}

Using this keyword as lock in concurrency

In the following program, does the this keywords in the LoggerThread class refer to LoggerThread object or LogService object? Logically it should refer to LogService in order for the syncronization to work, but semantically it seems it is referring to LoggerThread.
public class LogService {
private final BlockingQueue<String> queue;
private final LoggerThread loggerThread;
private final PrintWriter writer;
#GuardedBy("this") private boolean isShutdown;
#GuardedBy("this") private int reservations;
public void start() { loggerThread.start(); }
public void stop() {
synchronized (this) { isShutdown = true; }
loggerThread.interrupt();
}
public void log(String msg) throws InterruptedException {
synchronized (this) {
if (isShutdown)
throw new IllegalStateException("...");
++reservations;
}
queue.put(msg);
}
private class LoggerThread extends Thread {
public void run() {
try {
while (true) {
try {
synchronized (this) {
if (isShutdown && reservations == 0)
break;
}
String msg = queue.take();
synchronized (this) { --reservations; }
writer.println(msg);
} catch (InterruptedException e) { /* retry */ }
}
} finally {
writer.close();
}
}
}
}
Thank you for your help
this within LoggerThread methods refers to a LoggerThread instance.
LogService.this refers to the outer class.
Both isShutdown and reservations are synchronised by the different locks (LoggerThread.this and LogService.this), so #GuardedBy("this") doesn't reflect the reality.
This code is from the great book "Java Concurrency In Practice", Listing 7.15
It is a typo and is mentioned in "Errata" section:
http://jcip.net.s3-website-us-east-1.amazonaws.com/errata.html
this refers to the current instance of the immediately enclosing class. JLS #15.8.4.
Logically it should refer to LogService in order for the syncronization to work, but semantically it seems it is referring to LoggerThread.
Correct. It's a bug.

Stop the whole producer and consumer threads and yield the control to main thread

DefaultRunners are producers
and OrderTaker is a consumer
They both share a OrderQueue.
Currently, I use the variable isDone to indicate if a game is finished.
Once each round is done, I want to make it repeat again and again.
However, in my current implementation it will only run once.
How could I solve it?
public class OrderQueue {
public synchronized void pushOrder(Order order) throws InterruptedException {
if (isDone) {
wait();
} else {
runnersQueue.addLast(order);
notifyAll();
}
}
public void pullOrder() {
try {
if (runnersQueue.size() == 0) {
} else if (isDone) {
wait();
} else {
handleOrder(runnersQueue.pop());
}
} catch (InterruptedException e) {
}
}
In my main class
while(true){
enterYesToStart();
DefaultRunners dfltRunner = new DefaultRunners(queue);
OrderTaker taker = new OrderTaker(queue);
taker.run();
System.out.println("This round is finished"); # never reach to this line
}
Here's the full source code for the example
https://gist.github.com/poc7667/d98e3bf5b3b470fcb51e00d9a0d80931
I've taken a look at your code snippets and the problem is fairly obvious.
The main thread runs the OrderTaker runnable. The main thread is stuck in an eternal loop as the while statement cannot complete unless it throws an exception. (Note that the same is true for your ThreadRunner runnable.)
This means that the main thread i still pulling orders while the race is already done.
The OrderTaker should exit it's while loop while once the race is done. I guess that there are multiple ways achieve this, but one way is use a shared variable.
I took your code and adapted it into a working example.
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RaceApp {
public static void main(String[] args) throws InterruptedException {
final RaceUpdateManager queue = new RaceUpdateManager();
for (int i = 0; i < 3; i++) {
queue.reset();
List<Thread> threads = Arrays.asList(
new Thread(new Runner("Tortoise", 0, 10, queue)),
new Thread(new Runner("Hare", 90, 100, queue))
);
for (Thread thread : threads) {
thread.start();
}
RaceUpdatesProcessor processor = new RaceUpdatesProcessor(queue);
processor.run();
System.out.println("Game finished");
}
}
private static class RaceUpdateManager {
private static final int TOTAL_DISTANCE = 300;
//thread-safe implementation for queue so no external syncrhonization is required when adding/removing updates
private final Deque<RaceUpdate> runnersQueue = new ConcurrentLinkedDeque<>();
//lock used to sync changes to runnersRecords and done variables
private final ReadWriteLock raceStatusLock = new ReentrantReadWriteLock();
private final Map<String, Integer> runnersRecords = new HashMap<>();
private volatile boolean raceDone = false;//volatile keyword guarantees visibility of changes to variables across threads
public boolean isRaceDone() {
return raceDone;
}
//updates can by added simultaneously (read lock)
public void register(RaceUpdate raceUpdate) throws InterruptedException {
Lock readLock = raceStatusLock.readLock();
readLock.lock();
try {
if (!raceDone) {
runnersQueue.addLast(raceUpdate);
}//ignore updates when the race is done
} finally {
readLock.unlock();
}
}
//but they need to be processed in order (exclusive write lock)
public void processOldestUpdate() {
Lock writeLock = raceStatusLock.writeLock();
writeLock.lock();
try {
RaceUpdate raceUpdate = runnersQueue.poll();
if (raceUpdate != null) {
handleUpdate(raceUpdate);
}
} finally {
writeLock.unlock();
}
}
private void handleUpdate(RaceUpdate raceUpdate) {
Integer distanceRun = runnersRecords.merge(
raceUpdate.runner, raceUpdate.distanceRunSinceLastUpdate, (total, increment) -> total + increment
);
System.out.printf("%s: %d\n", raceUpdate.runner, distanceRun);
if (distanceRun >= TOTAL_DISTANCE) {
raceDone = true;
System.out.printf("Winner %s\n", raceUpdate.runner);
}
}
public void reset() {
Lock writeLock = raceStatusLock.writeLock();
writeLock.lock();
try {
runnersQueue.clear();
runnersRecords.clear();
raceDone = false;
} finally {
writeLock.unlock();
}
}
}
public static class Runner implements Runnable {
private final String name;
private final int rest;
private final int speed;
private final RaceUpdateManager queue;
private final Random rand = new Random();
public Runner(String name, int rest, int speed, RaceUpdateManager queue) {
this.name = name;
this.rest = rest;
this.speed = speed;
this.queue = queue;
}
#Override
public void run() {
while (!queue.isRaceDone()) {
try {
if (!takeRest()) {
queue.register(new RaceUpdate(this.name, this.speed));
}
Thread.sleep(100);
} catch (InterruptedException e) {
//signal that thread was interrupted and exit method
Thread.currentThread().interrupt();
return;
}
}
}
private boolean takeRest() {
return rand.nextInt(100) < rest;
}
}
public static class RaceUpdatesProcessor implements Runnable {
private final RaceUpdateManager queue;
public RaceUpdatesProcessor(RaceUpdateManager queue) {
this.queue = queue;
}
#Override
public void run() {
while (!queue.isRaceDone()) {
try {
queue.processOldestUpdate();
Thread.sleep(50);
} catch (InterruptedException e) {
//signal that thread was interrupted and exit method
Thread.currentThread().interrupt();
return;
}
}
}
}
public static class RaceUpdate {
public final String runner;
public final int distanceRunSinceLastUpdate;
public RaceUpdate(String runner, int distanceRunSinceLastUpdate) {
this.runner = runner;
this.distanceRunSinceLastUpdate = distanceRunSinceLastUpdate;
}
}
}

how to resolve deadlock causes by the synchronized method

I encountered the issue like the Deadlocks and Synchronized methods. In this case, methodA, methodB, A.last() all must be the synchronized method. So I am going to resolve this issue by removing synchronized in the method B.last(). Any deadlock in this solution? Could you please let me know any solution to resolve this better?
Class A
{
synchronized void methodA(B b)
{
b.last();
}
synchronized void last()
{
System.out.println(“ Inside A.last()”);
}
}
Class B
{
synchronized void methodB(A a)
{
a.last();
}
synchronized void last()
{
System.out.println(“ Inside B.last()”);
}
}
Class Deadlock implements Runnable
{
A a = new A();
B b = new B();
// Constructor
Deadlock()
{
Thread t = new Thread(this);
t.start();
a.methodA(b);
}
public void run()
{
b.methodB(a);
}
public static void main(String args[] )
{
new Deadlock();
}
}
In general, to avoid deadlocks, either use only one lock at all, or make sure that locks are always acquired in the same order.
Assuming that you decide A always has to be locked before B, a minimally invasive bugfix for your example (assuming that nothing else synchronizes against A or B objects) would be this in class B:
void methodB(A a) {
synchronized(a) {
synchronized(this) {
// do whatever was in methodB before, including...
a.last();
}
}
}
That way, if both locks are required, lock of A is always acquired first, causing no deadlocks.
You can also do the same with the Java 5+ java.util.concurrent locks. Removing a synchronized where not needed is of course also an option to solve the deadlock (but if synchronization was needed, it will cause race conditions instead which are usually worse than a deadlock).
You can use a common mutex such as a ReentrantLock or synchronized blocks between the two methods instead of synchronized.
ReentrantLock example:
Class A
{
A(Lock lock) {
this.lock = lock;
}
private Lock lock;
void methodA(B b)
{
lock.lock();
try {
b.last();
} finally {
lock.unlock();
}
}
void last()
{
lock.lock();
try {
System.out.println(“ Inside A.last()”);
} finally {
lock.unlock();
}
}
}
Class B
{
B(Lock lock) {
this.lock = lock;
}
private Lock lock;
void methodB(A a)
{
lock.lock();
try {
a.last();
} finally {
lock.unlock();
}
}
void last()
{
lock.lock();
try {
System.out.println(“ Inside B.last()”);
} finally {
lock.unlock();
}
}
}
Class Deadlock implements Runnable
{
Lock lock = new ReentrantLock();
A a = new A(lock);
B b = new B(lock);
// Constructor
Deadlock()
{
Thread t = new Thread(this);
t.start();
a.methodA(b);
}
public void run()
{
b.methodB(a);
}
public static void main(String args[] )
{
new Deadlock();
}
}
synchronized block example:
Class A
{
A(Object lock) {
this.lock = lock;
}
private Object lock;
void methodA(B b)
{
synchronized(lock){
b.last();
}
}
void last()
{
synchronized(lock){
System.out.println(“ Inside A.last()”);
}
}
}
Class B
{
B(Object lock) {
this.lock = lock;
}
private Object lock;
void methodB(A a)
{
synchronized(lock){
a.last();
}
}
void last()
{
synchronized(lock){
System.out.println(“ Inside B.last()”);
}
}
}
Class Deadlock implements Runnable
{
Object lock = new Object();
A a = new A(lock);
B b = new B(lock);
// Constructor
Deadlock()
{
Thread t = new Thread(this);
t.start();
a.methodA(b);
}
public void run()
{
b.methodB(a);
}
public static void main(String args[] )
{
new Deadlock();
}
}

IllegalMonitorStateException raised with explicit lock/condition

I want to have such kind of work flow using explicit lock/condition variables (It's a course project which mandates this style.): A is the main class, it asks B to do some job from time to time. B has a worker class C which constantly queries B about new jobs to do and do it. After C finishes, it will call A's callback function to notify A the job is done.
However when I try to run the program, I get an IllegalMonitorStateException, when the callback() is trying to notify the doit() function.
exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Test$A.callback(Test.java:49)
at Test$C.run(Test.java:115)
I looked at the javadoc and some Q&A about this exception, but still no idea why I get this.
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
public class Test {
public class A
{
private ReentrantLock lock;
private Condition cond;
private boolean bool;
private B b;
public A()
{
this.lock = new ReentrantLock();
this.cond = lock.newCondition();
b = new B(this);
bool = false;
}
public void doit()
{
try {
lock.lock();
b.letgo();
while (!bool) {
System.out.println("A::doit() Block.");
cond.awaitUninterruptibly();
}
System.out.println("A::doit() Done.");
}
finally {
lock.unlock();
}
}
public void callback() {
try {
lock.lock();
bool = true;
cond.notify();
System.out.println("A::callback() done.");
}
finally {
lock.unlock();
}
}
}
public class B
{
private C c;
private ReentrantLock lock;
private Condition cond;
private boolean bool;
public B(A a)
{
this.lock = new ReentrantLock();
this.cond = lock.newCondition();
bool = false;
c = new C(a, this);
c.start();
}
public void letgo()
{
try {
lock.lock();
bool = true;
}
finally {
lock.unlock();
}
}
public void get()
{
try {
lock.lock();
while (!bool) {
cond.awaitUninterruptibly();
}
bool = false;
return;
}
finally {
lock.unlock();
}
}
}
public class C extends Thread
{
private A a;
private B b;
public C(A a, B b)
{
this.a = a;
this.b = b;
}
public void run()
{
while (true) {
b.get();
a.callback();
}
}
}
public static void main(String args[])
{
Test t = new Test();
t.test1();
}
public void test1()
{
A a = new A();
a.doit();
}
}
Use the signal() method on Condition in place of notify().
While you can successfully synchronize on a Condition instance, and then use the traditional wait() and notify() methods, you might as well just use an Object if you aren't using the extended capabilities of the concurrent classes.
Condition was intended to be used with the equivalent methods await() and signal(), and their enhanced variants.

Categories

Resources