I have a class named "Channel" with two methods defined:
class Channel {
void read(){...}
void write(){...}
}
There's an instance of this class used in multi-threaded environment. Several threads periodically read from channel while one thread periodically writes to it. Read operation is thread-safe so that it is ok for several reads to occur simultaneously. However once write operation starts, read threads must be blocked until write operation is finished. It is essential to keep read operations as fast as possible and avoid resource-consuming synchronization routines.
What would be the most appropriate pattern to implement such behaviour? Maybe java classes or libraries to help?
Use a ReadWriteLock. It will allow concurrent reads to occur with serial writes. To further satisfy your requirements, an acquisition of a writeLock will prevent any readLock's from making progress until a subsequent release.
class Channel {
final ReadWriteLock lock = new ReentrantReadWriteLock();
void read(){
lock.readLock().lock();
try{
}finally{
lock.readLock().unlock();
}
}
void write(){
lock.writeLock().lock();
try{
}finally{
lock.writeLock().unlock();
}
}
}
For fun, here's an implementation using the new Java 7 try-with-resources feature.
class RWLock {
class ACLock extends ReentrantLock implements AutoCloseable {
public void close() {
this.unlock();
}
}
private ACLock readLock = ACLock();
private ACLock writeLock = ACLock();
private int numReaders = 0
public AutoCloseable write() {
readLock.lock();
writeLock.lock();
return new AutoCloseable() {
public void close() {
writeLock.close();
readLock.close();
}
}
}
public AutoCloseable read() {
try (ACLock read = readLock.acquire()) {
if (numReaders == 0) {
writeLock.lock();
}
numReaders++;
}
return new AutoCloseable() {
public void close() {
numReaders--;
if (numReaders == 0) {
writeLock.unlock();
}
}
}
}
// Here's how you use them
public static void main(String[] args) {
RWLock lock = RWLock();
try (AutoCloseable lock = RWLock.read()) {
// Do some readin'
}
try (AutoCloseable lock = RWLock.write()) {
// Do some writin'
}
}
}
Related
class PublishService {
public void longRunningPublish() {
...
}
}
From different places in code, the method can be invoked.
caller1.longRunningPublish();
caller2.longRunningPublish();
...
callerN.longRunningPublish();
Question: how can I prevent longRunningPublish running concurrently? Each invocation should stack and be delay, and only start when the previous run has finished.
Could I do better than the following?
class PublishService {
private boolean running;
public void throttleLongRunningPublish() {
while (running) {
TimeUnit.SECONDS.sleep(10);
}
running = true;
try {
longRunningPublish();
} finally {
running = false;
}
}
}
Your code is not thread safe.
If you create multiple instances of PublishService and run them concurrently the boolean variable has no effect.
If your instance of PublishService is a singleton and the same class is executed by different threads there there is no guarantee that the method will be executed serially because multiple thread could enter the method before reaching the instruction:
running = true;
This is a simple example than handles serialization if there are multiple instances of the same class along with a "demo" main
public class PublishService {
private static final Logger logger= LoggerFactory.getLogger(PublishService.class.getName());
private static final Lock lock=new ReentrantLock();
public void longRunningPublish() {
lock.lock();
try {
logger.info("{} longRunningPublish before sleep",Thread.currentThread().getId());
Thread.sleep(500);
logger.info("{} longRunningPublish after sleep",Thread.currentThread().getId());
} catch (InterruptedException e) {
logger.error(e.getMessage(),e);
} finally {
lock.unlock();
}
}
public static void main(String args[]) {
ExecutorService executor=Executors.newFixedThreadPool(10);
for(int i=0;i<20;i++) {
executor.submit(() -> {
PublishService publishService = new PublishService();
publishService.longRunningPublish();
});
}
}
}
If the class is a singleton you can remove the static qualifier of the lock variable.
In order to prevent concurrent access, you need to lock the resource while it is being used with something like a ReentrantLock. If you need to guarantee in-order access, you can use the constructor ReentrantLock(boolean fair) with fair set to true. Otherwise, you can use a basic ReentractLock or the synchronized property.
I found a neat way with Semaphore:
class PublishService {
private static final Semaphore lock = new Semaphore(1);
public void throttleLongRunningPublish() {
try {
lock.tryAcquire(2, TimeUnit.MINUTES);
longRunningPublish();
} finally {
lock.release();
}
}
}
I have two synchronized methods, each of them is being executed by a different Thread.
public synchronized ResultSet dbExecuteQuery(String queryStmt);
public synchronized void dbExecuteUpdate(String queryStmt);
How can I make sure their execution won't "overlap"?
One solution that comes to my mind is the following:
public synchronized ResultSet dbExecute(String queryStmt, boolean isUpdate) {
if (isUpdate) {
dbExecuteUpdate(queryStmt);
return null;
} else
return dbExecuteQuery(queryStmt);
}
But it means I would have to change all code used in the whole project. Is there a cleaner way to do it?
You can add a dedicated synchronization object:
class YourClass {
Object syncObject = new Object();
public ResultSet dbExecuteQuery(String queryStmt) {
synchronized(syncObject) {
// your code
}
}
public void dbExecuteUpdate(String queryStmt) {
synchronized(syncObject) {
// other code
}
}
}
But it's probably better to use a ReentrantLock.
class YourClass {
private Lock lock = new ReentrantLock();
public ResultSet dbExecuteQuery(String queryStmt) {
lock.lock();
// your code
lock.unlock();
}
public void dbExecuteUpdate(String queryStmt) {
lock.lock();
// other code
lock.unlock();
}
}
Actually, since one is a read and one a write, you probably want to use ReadWriteLock.
class YourClass {
private ReadWriteLock lock = new ReentrantReadWriteLock();
public ResultSet dbExecuteQuery(String queryStmt) {
lock.readLock().lock();
// your code
lock.readLock()..unlock();
}
public void dbExecuteUpdate(String queryStmt) {
lock.writeLock()..lock();
// other code
lock.writeLock().unlock();
}
}
This way you can have several threads reading concurrently:
The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.
I'm looking for a solution that allows multiple threads to read the shared resource (concurrency permitted) but then locks these reading threads once a thread enters a mutating block, to achieve best of both world.
class Foo {
Map<String, String> sharedResource;
public void read() // multiple reading threads allowed, concurrency ok, lock this only if a thread enters the mutating block below.
{
// read concurrently unless a thread enters mutating blocks add/remove
}
public void add() // this should lock any threads entering this block as well as lock the reading threads above
{
synchronized(sharedResource) // lock remove and read
{
}
}
public void remove() // lock add and read
{
synchronized(sharedResource)
{
}
}
}
Is there such a solution in Java?
It's a classic read/write lock scenario:
class Foo {
Map<String, String> sharedResource;
ReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
lock.readLock().lock();
try {
// read
} finally {
lock.readLock().unlock();
}
}
public void add() {
lock.writeLock().lock();
try {
// add
} finally {
lock.writeLock().unlock();
}
}
public void remove() {
lock.writeLock().lock();
try {
// remove
} finally {
lock.writeLock().unlock();
}
}
}
The read lock can be shared, but the write lock is exclusive to both reads and writes.
This question already has answers here:
How do determine if an object is locked (synchronized) so not to block in Java?
(8 answers)
Closed 6 years ago.
I have synchronisation block in syncCmd function:
public Object Sync = new Object();
public void syncCmd(String controlCmd) {
synchronized(Sync) {
...
}
}
I need to add some logic in case if one thread has occupied Sync and doing its job. In this case I would like to report "too busy" to system and not get to queue. What is the best way to know if somebody has occupied Sync section? How to know how many threads is waiting in this section? Everything is in Java 1.4.
Have a look at the Lock interface and its implementation ReentrantLock. It allows you to use tryLock() method, including the variant that allows to wait for some time if the resource is already locked:
private ReentrantLock lock = new ReentrantLock();
public void syncCmd(String controlCmd) {
if (lock.tryLock()) {
try {
// Use your synchronized resource here
} finally {
lock.unlock();
}
} else {
// Failed to lock
}
}
Java 1.4, unfortunately, has no java.util.concurrency package and I think the best choice you have is to implement the same logic by means of synchronized and double checks:
public class Lock {
private final Object lock = new Object();
private volatile boolean locked = false;
public boolean tryLock() {
if (!locked) {
synchronized (lock) {
if (!locked) {
locked = true;
return true;
}
}
}
return false;
}
public void unlock() {
synchronized (lock) {
locked = false;
}
}
}
It will not work as fast as ReentrantLock that uses CAS loop backed by processor instructions in modern JVMs, but it will do the job.
This implementation is also not reentrant, you can extend it to track the locking thread and locks count if you need reentrance.
Important update: #Stephen C made a good point that double check is broken in Java 1.4 and one always must keep it in mind. But there're exceptions. For instance, short primitive types. So, I think it will work in this particular case. For more details, please, look at the "Double-Checked Locking is Broken" Declaration.
Synchronized blocks / methods and primitive mutexes can't do that in Java.
But if you use a Lock instead (javadoc), you can use tryLock either to never block or to only block for a limited time.
Example:
Lock l = new ReentrantLock();
if (l.tryLock()) {
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
else {
// report "too busy"
}
But note that it is essential to use "try ... finally" and an explicit unlock() call to ensure that the lock is always released. (Unlike the synchronized constructs, which takes care of that for you automatically.)
Prior to Java 1.5 there is no solution that I am aware of in pure Java. It might be possible with native code trickery, but I don't know how.
You / your management should be looking to ditch support in your products for Java 1.4, and to migrating away from any third-party product that depends on top of it. Java 1.5 itself was EOL'd many years ago. In fact, all releases prior to Java 1.8 have been EOL'd; see the Oracle Java SE Support Roadmap document.
Two of the answers above talked about java.util.concurrent.locks.ReentrantLock, but it doesn't exist in Java 1.4.
Too bad so sad?
No! If system libraries and 3rd party libraries don't hand you what you want, then write it yourself!
The code below does what you asked for, and absolutely nothing more. I personally would not use it without first adding some features that would make it more useable, more testable, and most importantly, more foolproof.
I'm just offering it to you as an example of where to begin.
public class ExtremelySimplisticNonReentrantLock {
boolean isLocked = false;
/**
* #return true if the lock was acquired, false otherwise.
*/
public synchronized boolean tryToAcquire() {
if (isLocked) {
return false;
}
isLocked = true;
return true;
}
public synchronized void release() {
lsLocked = false;
}
}
Share and Enjoy!
Try this (Two classes - Executor and Tracker ) :
Executor :
package com.example.so.jdk1_4.synch;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p>
* #author Ravindra HV
*/
public class InUseExample {
public synchronized void execute(String command) {
InUseTracker.obtainClassInstance().setInuse(true);
try {
System.out.println("Executing :"+command);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}// do work
InUseTracker.obtainClassInstance().setInuse(false);
}
/**
* #param args
*/
public static void main(String[] args) {
System.out.println("Start :"+new Date());
testInUseExample();
System.out.println("Final wait count :"+InUseTracker.obtainClassInstance().waitCount());
System.out.println("End :"+new Date());
}
private static void testInUseExample() {
final InUseExample inUseExample = new InUseExample();
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
InUseTracker.obtainClassInstance().incrementWaitCount();
while(true) {
if( InUseTracker.obtainClassInstance().isInuse() == false ) { // reduces the chances of this thread going to a block mode..
inUseExample.execute(Thread.currentThread().getName());
break;
}
else {
try {
Random random = new Random();
String message = Thread.currentThread().getName()+" - block in use by :"+InUseTracker.obtainClassInstance().getInUseBy();
message = message+" "+". Wait Count :"+InUseTracker.obtainClassInstance().waitCount();
System.out.println(message);
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
InUseTracker.obtainClassInstance().decrementWaitCount();
}
}
};
int threadCount = 10;
List<Thread> threadPoolTemp = new ArrayList<Thread>();
for(int i=0;i<threadCount;i++) {
Thread thread = new Thread(runnable);
threadPoolTemp.add(thread);
}
for (Thread thread : threadPoolTemp) {
thread.start();
}
for (Thread thread : threadPoolTemp) {
try {
thread.join(); // wait until all threads have executed..
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Tracker :
package com.example.so.jdk1_4.synch;
/**
* <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p>
* #author Ravindra HV
*/
public class InUseTracker {
private boolean inuse;
private int waitCount;
private String inUseBy;
private static InUseTracker DEFAULT_INSTANCE = new InUseTracker();
private InUseTracker() {
}
public static InUseTracker obtainClassInstance() {
return DEFAULT_INSTANCE;
}
public synchronized boolean isInuse() {
return inuse;
}
public synchronized void setInuse(boolean inuse) {
this.inuse = inuse;
if(inuse) {
setInUseBy(Thread.currentThread().getName());
}
else {
setInUseBy("");
}
}
private void setInUseBy(String inUseBy) {
this.inUseBy = inUseBy;
}
public synchronized String getInUseBy() {
return inUseBy;
}
public synchronized void incrementWaitCount() {
waitCount++;
}
public synchronized void decrementWaitCount() {
waitCount--;
}
public synchronized int waitCount() {
return waitCount;
}
}
PS: Guess you'd have to move the
InUseTracker.obtainClassInstance().setInuse(false);
within a finally if or as appropriate.
I have wrote following wrapepr:
public class AutoCloseableLockWrapper implements AutoCloseable, Lock{
private final Lock lock;
public AutoCloseableLockWrapper(Lock l) {
this.lock = l;
}
#Override
public void lock() {
this.lock.lock();
}
#Override
public void lockInterruptibly() throws InterruptedException {
lock.lockInterruptibly();
}
#Override
public boolean tryLock() {
return lock.tryLock();
}
#Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return lock.tryLock(time,unit);
}
#Override
public void unlock() {
lock.unlock();
}
#Override
public Condition newCondition() {
return lock.newCondition();
}
#Override
public void close() {
this.lock.unlock();
}
}
In my code I use it like this:
public class ReadWriteMap implements Map {
private HashMap map = new HashMap();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
#Override
public int size() {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.size();
}
}
#Override
public boolean isEmpty() {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.isEmpty();
}
}
#Override
public boolean containsKey(Object key) {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.containsKey(key);
}
}
...
}
I don't want to create wrapper in each method.
Is there way to combine single wrapper and try with resources ?
You are over-complicating your design. If your AutoCloseableLockWrapper intentionally exposes all operations supported by the underlying Lock, there is no point in making it private and adding delegation methods for each of Lock’s methods. You could simply make the Lock reference public to allow its use, or leave it off entirely, as the code which creates the wrapper already has a reference to the Lock.
All you want to do, is to support a single operation, unlock, which should be viewed as AutoCloseable.
A Java 8 solution may look like
import java.util.concurrent.locks.Lock;
public interface AutoUnlock extends AutoCloseable {
public static AutoUnlock lock(Lock lock) {
lock.lock();
return lock::unlock;
}
#Override
public void close(); // no checked exceptions
}
It can be used like:
Lock lock=…
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
// critical code
}
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
// critical code
}
If you worry about the instance creation (usually this is not an issue), you can re-use AutoCloseables:
AutoUnlock reusable=lock::unlock;
// …
lock.lock();
try(AutoUnlock u=reusable) {
// critical code
}
// …
lock.lock();
try(AutoUnlock u=reusable) {
// critical code
}
To me, it looks less clear since the lock(); and try statements are not syntactically coupled and could be separated by accident. But if the lock has a non-local scope, you could solve this by creating a utility method:
final Lock lockInstance; // this field name is to prevent confusion with the lock() method
final AutoUnlock reusable;
YourConstructor(Lock lock) {// you may get the Lock as a parameter
lockInstance=lock; // or create one here, right in the constructor
reusable=lockInstance::unlock;
}
AutoUnlock lock() {
lockInstance.lock();
return reusable;
}
void doSomething() {
// …
try(AutoUnlock u=lock()) {
// critical code
}
// …
try(AutoUnlock u=lock()) {
// critical code
}
}
I think, it’s not too hard to back-port this logic into Java 7 code, if needed.
You can use a factory method that returns a singleton. Nothing is forcing you to use a constructor.
BTW you should not call lock inside the try-block. That should have already happened in the "acquire the resource" phase (within the constructor in your current design, inside the factory method in my proposal).
I see that the above note is already posted on the Q&A page where you contributed your wrapper. The page already has very good content; I advise to study it well.
I'd prefer just creating a new lock (not a wrapper around a lock):
public class AutoReentrantLock implements AutoCloseable {
private final ReentrantLock lock = new ReentrantLock();
public AutoReentrantLock lock() {
lock.lock();
return this;
}
public void earlyUnlock() {
lock.unlock();
}
#Override
public void close() {
if(lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
Use like this:
private AutoReentrantLock consistencyLock = new AutoReentrantLock();
try(AutoReentrantLock lock = consistencyLock.lock()) {
// other code
}
Or a more complicated use case, where you unlock halfway:
private AutoReentrantLock consistencyLock = new AutoReentrantLock();
try(AutoReentrantLock lock = consistencyLock.lock()) {
// Place code here that gathers information (while under lock)
// but may exit early or throw exceptions
lock.earlyUnlock();
// ... followed by code that is slow that acts upon above gathered information.
}