Imagine a Java class with three methods:
master()
foo()
bar()
I want to synchronize master() and foo() and also master() and bar(), without synchronizing foo() and bar(). It can be done will a separate lock for every pair of synchronized methods, but my actual code has many more than three methods so I was hoping there's a way to do it without so many lock objects.
You are essentially describing a ReadWriteLock. Every two methods are allowed to run simultaneously (a "read lock"), except for master(), which excludes all others (a "write lock"):
public class MyClass {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock r = rwLock.readLock();
private final Lock w = rwLock.writeLock();
public void master() {
w.lock();
// do stuff
w.unlock();
}
public void foo() {
r.lock();
// do stuff
r.unlock();
}
public void bar() {
r.lock();
// do stuff
r.unlock();
}
}
You can use synchronized on any Object. So, you can create a separate lock for the methods:
public class Lock {
private final Object master_foo = null;
private final Object master_bar = null;
public void master() {
synchronized(master_foo) {
synchronized(master_bar) {
...
}
}
}
public void foo() {
synchronized(master_foo) {
...
}
}
public void bar() {
synchronized(master_bar) {
...
}
}
}
I would go with Mureinik's answer, but just for the heck of it, here's another way you can set up read/write synchronization (untested):
public class Test {
private final Semaphore semaphore = new Semaphore(Integer.MAX_VALUE);
public void master() {
semaphore.acquireUninterruptibly(Integer.MAX_VALUE);
try {
//...
} finally {
semaphore.release(Integer.MAX_VALUE);
}
}
public void foo() {
semaphore.acquireUninterruptibly();
try {
//...
} finally {
semaphore.release();
}
}
public void bar() {
semaphore.acquireUninterruptibly();
try {
//...
} finally {
semaphore.release();
}
}
}
Related
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.
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();
}
}
I whould like to block a method execution from more thab 3 threads. The method can be executed recursively. I have following agly code. Can I achive this by using better way?
private static class MyHolder {
private static Semaphore limitThreadsSemaphore = new Semaphore(3);
private static Set<Thread> asquiredThreads = new HashSet<Thread>();
}
#Override
public void someMethod() {
if (!MyHolder.asquiredThreads.contains(Thread.currentThread())) {
synchronized (MyHolder.asquiredThreads) {
if (!MyHolder.asquiredThreads.contains(Thread.currentThread())) {
try {
MyHolder.limitThreadsSemaphore.acquire();
MyHolder.asquiredThreads.add(Thread.currentThread());
} finally {
MyHolder.limitThreadsSemaphore.release();
MyHolder.asquiredThreads.remove(Thread.currentThread());
}
}
}
}
return super.someMethod();
}
Thanks.
The simplest approach would be to refactor the recursive method to be private and then have the public method unconditionally acquire the semaphore, call the private method and then release the semaphore again. The recursive calls route straight to the private method so don't go through the semaphore guard code.
If that is not an option then the simplest approach I can think of would be to use a ThreadLocal flag
ThreadLocal<Object> alreadyIn = new ThreadLocal<>();
public void someMethod() {
boolean needSem = (alreadyIn.get() == null);
if(needSem) {
semaphore.acquire();
alreadyIn.set(new Object());
}
try {
// do stuff
} finally {
if(needSem) {
alreadyIn.remove();
semaphore.release();
}
}
}
I guess "someMethod" is the method you want to block execution,yeah?. Why don'y you do this? :
private static class MyHolder {
private static Semaphore limitThreadsSemaphore = new Semaphore(3);
public boolean semaphoreAdquired = false; //Make it private
public Semaphore getSemaphore()
{
return limitThreadsSemaphore;
}
}
#Override
public void someMethod() {
boolean ReleaseSemaphore = false;
if(!semaphoreAdquired)
{
MyHolder.getSemaphore().acquire();
semaphoreAdquired = true;
ReleaseSemaphore = true;
}
super.someMethod();
if(ReleaseSemaphore)
{
MyHolder.getSemaphore().release();
semaphoreAdquired = false;
}
}
Based on the documentation for Semaphor, this should be achievable using only acquire() and release() around the critical section. Also, you should be able to put the semaphor in the current class, no need for a separate class to contain the Semaphor.
private static Semaphore limitThreadsSemaphore = new Semaphore(3);
#Override
public void someMethod() {
limitThreadsSemaphore.acquire();
// do work.
limitThreadsSemaphore.release();
}
Update: If you need to call a method recursively within a thread, then the easiest way is to use a helper method to acquire the semaphor, and then invoke the recursive method from that helper method after acquiring the sempahor. You would call the helper instead of the original method in all the initial calls.
private static Semaphore limitThreadsSemaphore = new Semaphore(3);
public void someMethodHelper() {
limitThreadsSemaphore.acquire();
someMethod();
limitThreadsSemaphore.release();
}
#Override
public void someMethod() {
// do work, with recursive calls.
}
Suppose there is the following code:
class MyClass {
synchronized void myMethod1() {
//code
}
synchronized void myMethod2() {
//code
}
}
Now suppose myMethod1() and myMethod2() access distinct data; now if there are two threads, thread A calling only myMethod1() and thread B calling only myMethod2().
If thread A is executing myMethod1(), will thread B block waiting on myMethod2() even if they don't access the same data and there is no reason for this? As far as I know, synchronized methods use the monitor of this object for instance methods and that of MyClass.class object for static functions.
Your understanding of the situation is correct.
The typical solution is to have separate dedicated lock objects for the resources in question.
class MyClass {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
void myMethod1() {
lock1.lock();
try {
//code
} finally {
lock1.unlock();
}
}
void myMethod2() {
lock2.lock();
try {
//code
} finally {
lock2.unlock();
}
}
}
You are correct in all your suppositions. In the case where no data is in common then there is no reason to synchronize at the method level.
The sychronized method will lock on the object itself. So each method will have to wait for the other to finish its access to release the object. If your methods are truly accessing distinct data you can do something like this:
class MyClass {
private static Object mLock1 = new Object();
private static Object mLock2 = new Object();
void myMethod1() {
synchronized(mLock1) {
//code
}
}
void myMethod2() {
synchronized(mLock2) {
//code
}
}
}
And you can then access them independently.
edit: You can essentially think of synchronized methods as being equivalent to this:
void myMethod1() {
synchronized(this) {
//your code
}
}
Shown like this it is pretty clear why two synchronized methods block each other because they have to wait for the lock on this to free.
Yes, declaring both methods as synchronized will make them block each other, even if they access different data elements.
To avoid this, you can use a more fine grained locks. E.g.:
class MyClass {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
void myMethod1() {
synchronized (lock1) {
//code
}
}
void myMethod2() {
synchronized (lock2) {
//code
}
}
You can use different monitors for myMethod1 and myMethod2 as follows:
class MyClass {
Object monitor1 = new Object();
Object monitor2 = new Object();
void myMethod1() {
synchornized(monitor1) {
//code
}
}
void myMethod2() {
synchronized(monitor2) {
//code
}
}
}
Suppose I have a class like this:
package com.spotonsystems.bulkadmin.cognosSDK.util.Logging;
public class RecordLogging implements LittleLogging{
private LinkedList <String> logs;
private boolean startNew;
public RecordLogging() {
logs = new LinkedList<String>();
}
public void log(String log) {
logHelper(log);
startNew = true;
}
public void logPart(String log) {
logHelper(log);
startNew = false;
}
private void logHelper(String log){
// DO STUFF
}
public LinkedList<String> getResults() {
return logs;
}
}
Now suppose that I need a thread safe version of this code. I need the tread safe version to implement LittleLogging. I want the thread safe copy to have the same behavior as this class except I would like it to be thread safe. Is it safe to do this:
package com.spotonsystems.bulkadmin.cognosSDK.util.Logging;
public class SyncRecordLogging extends RecordLogging {
public SyncRecordLoging() {
super();
}
public syncronized void log(String log) {
super.log(log);
}
public syncronized void logPart(String log) {
super.log(log);
}
public syncronized LinkedList<String> getResults() {
return logs;
}
}
Bonus Question: Where should I look for documentation about syncronization and threading
You can use composition instead. Also note that getResults creates a copy of the list:
public class SyncRecordLogging implements LittleLogging{
private final RecordLogging _log;
public SyncRecordLogging() {
_log = new RecordLogging();
}
public synchronized void log(String log) {
_log.log(log);
}
public synchronized void logPart(String log) {
_log.logPart(log);
}
public synchronized LinkedList<String> getResults() {
// returning copy to avoid 'leaking' the enderlying reference
return new LinkedList(_log.getResults());
}
}
Best read: Java Concurrency In Practice