What exactly gets locked when using APIs in java.util.concurrent.Locks? - java

This is probably a very silly question. I am reading through the documentation of interfaces and classes in packages java.util.concurrent.atomic and java.util.concurrent.locks. I find everywhere that
void lock() – acquire the lock if it’s available; if the lock isn’t available a thread gets blocked until the lock is released
What I am not sure about is, what resource is exactly getting locked? The code snippet examples show
Lock lock = new ReentrantLock();
lock.lock();
try {
// access to the shared resource
} finally {
lock.unlock();
}
Does whatever that is used under the call of lock() get locked? How does JVM know that before getting to that line? And what if there are multiple resources between lock() and unlock()? I guess I am having this question because I am reading this right after reading synchronization and it has very specific way of saying what to lock - like: synchronized(resourceReferenceThatNeedsToBeLocked)
I reseached a lot and yet can't find answer for this question.

You can think of your code like an optimised version of synchronized. You are "synchronizing" on your lock object, but in a more efficient way.
Note that when you're using synchronized, there are no guarantees regarding the resources used inside of the synchronized block. You are just locking on a specific object, which may or may not be the same resources you are using inside of the synchronized block. In essence, regardless of lock or synchronized, you're just saying "make sure no other thread can access the code (or other code guarded by the same lock or ´synchronized´ on the same instance) inside of this block until I'm finished".
The key thing to understand, regardless of lock or synchronized, is that you're guarding a block of code from concurrent access. The code inside the block may access one or several different resources; if the same resources are used elsewhere, access to them needs to be guarded with the same lock or be synchronized on the same instance in order to be safe.

Lock is always associated with data. If there's no data, synchronization is pointless. You have object Thread, Lock, Condition and so on. And then you have data structure that is synchronized with the help of this objects. You need full example. In sample bellow, I'm synchronizing a queue, so that data added to it is always synchronized. Of course it's added to queue from different threads
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class BackgroundWorker {
private Worker worker;
private StringBuilder allData;
#Before
public void setUp() throws Exception {
worker = new Worker(allData); // start databse worker
worker.start();
}
#After
public void tearDown() throws Exception {
worker.stop();
}
public void logValue(final String data) {
final LogValue logValue = new LogValue(data);
worker.queue(logValue);
}
#Test
public void test() {
// very dummy, NOT multithreaded test
for (int i = 0; i < 10; i++) {
logValue("Some data " + i);
}
}
private static class Worker implements Runnable {
private static final int MAX_QUEUE_SIZE = 1000;
private final Deque<Job> queue = new LinkedList<Job>();
private final Lock lock = new ReentrantLock();
private final Condition jobAdded = lock.newCondition();
private final Condition jobRemoved = lock.newCondition();
private final StringBuilder dataSource;
private final AtomicBoolean running = new AtomicBoolean(false);
private Thread thread = null;
Worker(final StringBuilder dataSource) {
this.dataSource = dataSource;
}
#Override
public void run() {
processing: for (;;) {
Job job;
lock.lock();
try {
while (null == (job = queue.pollFirst())) {
if (!running.get()) break processing;
try {
jobAdded.await();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
jobRemoved.signal();
}
finally {
lock.unlock();
}
job.run(dataSource);
}
}
void start() {
lock.lock();
try {
if (running.getAndSet(true)) return; // already running
thread = new Thread(this, "Database worker");
thread.start();
}
finally {
lock.unlock();
}
}
void stop() {
Thread runningThread;
lock.lock();
try {
if (!running.getAndSet(false)) return; // already stopped
runningThread = thread;
thread = null;
jobAdded.signal();
}
finally {
lock.unlock();
}
// wait for the thread to finish while not holding a lock
try {
runningThread.join(2000); // we give it 2 seconds to empty its queue
} catch (InterruptedException e) {
e.printStackTrace();
}
runningThread.interrupt(); // we interrupt it just in case it hasn't finished yet
}
void queue(final Job job) {
if (!running.get()) throw new IllegalStateException("Worker thread is not running");
lock.lock();
try {
while (queue.size() >= MAX_QUEUE_SIZE) {
try {
jobRemoved.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.addLast(job);
jobAdded.signal();
}
finally {
lock.unlock();
}
}
}
private static interface Job {
void run(StringBuilder dataSource);
}
private static class LogValue implements Job {
final String myData;
LogValue(final String data) {
this.myData = data;
}
#Override
public void run(final StringBuilder dataSource) {
dataSource.append(this.myData);
}
}
}

To answer my question:
The object that is locked is the object that reference variable lock is referring to. In this case a ReentrantLock object.
An important thing to note:
The code above is potentially misguiding. Creating a new lock object in a method would be done by respective threads, and the respective thread will only lock that was created in it's stack. If you want to lock a particular instance's variables or methods, that instance should have its own lock object and only that same lock object should be used for synchronisation.
Refer this question for more info. Refer this documentation of the lock in question.

Related

Java - Allow one thread in a method without waiting

I've a situation where I need to implement a thread safe method, The method must be executed by only one thread at a time, And while the method is being executed by a thread, all other threads trying to execute the same method shouldn't wait and must exit the method.
Synchronization won't help here since threads will be waiting to execute the method sequentially.
I thought I would achieve this by making use of ConcurrentHashMap using below code, but not sure if this is the perfect way to implement it.
Class Test {
private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
public void execute() {
if (map.putIfApsent("key", new Object()) != null) { // map has value for key which means a thread has already entered.
return; // early exit
}
threadSafeMethod();
map.remove("key");
}
private void threadSafeMethod() {
// my code
}
}
You can do this without synchronization, with compare-and-swap using a boolean:
private AtomicBoolean entered = new AtomicBoolean(false);
public void execute() {
if(entered.compareAndSet(false,true) {
try {
method()
} finally {
entered.set(false)
}
}
}
You could use a ReentrantLock and specify a negative value for waiting time. In that case the scheduler will not try to wait if there is a thread already executing the code.
// define the lock somewhere as an instance variable
Lock lock = new ReentrantLock();
try {
var isAvailable = lock.tryLock(-1, TimeUnit.NANOSECONDS);
if(isAvailable) {
System.out.println("do work");
lock.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
}

wait/notify vs sleep/interrupt vs ReentrantLock.Condition

I'm writing a search-as-you-type mechanism (android) that makes an sqlite query in a background thread and posts the results back to the UI thread. Ideally, the thread should wait/sleep, wake up to execute any received Runnable object and go back to sleep. what's the best way to achieve this and why?
Basically I want to understand what are the key differences between these 3 options and which one is best for this exact scenario
sleep/interrupt
public class AsyncExecutorSleepInterrupt {
private static Thread thread;
private static Runnable runnable;
static {
thread = new Thread(() -> {
while (true) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
if (runnable != null) {
runnable.run();
runnable = null;
}
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorSleepInterrupt.runnable = runnable;
thread.interrupt();
}}
wait/notify
public class AsyncExecutorWaitNotify {
private static Thread thread;
private static Runnable runnable;
private static final Object monitor = new Object();
static {
thread = new Thread(() -> {
while (true) {
synchronized (monitor) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
if (runnable != null) {
runnable.run();
runnable = null;
}
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorWaitNotify.runnable = runnable;
synchronized (monitor) {
monitor.notify();
}
}}
ReentrantLock
public class AsyncExecutorLockCondition {
private static final ReentrantLock lock = new ReentrantLock();
private static final Condition cond = lock.newCondition();
private static Thread thread;
private static Runnable runnable;
static {
thread = new Thread(() -> {
while(true){
try {
lock.lock();
cond.await();
runnable.run();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorLockCondition.runnable = runnable;
lock.lock();
cond.signal();
lock.unlock();
}}
Personally, I sort of dislike the first approach, probably because of interrupt mainly. What if someone, something calls and interrupts that thread somehow? You would be running some arbitrary code, probably not the best idea. Also, when you interrupt, you are actually filling the stack trace with exception chains, this is the most expensive part from an Exception being thrown.
But supposing you don't care about the second point, and you are totally in control of the first; there's probably nothing wrong with this approach IMO.
Now the difference between Conditional and wait/notify in this example is rather small. I don't know the internal details and which might be faster or better, but in general Conditional is preferred; mainly for the reason that it's easier to read, at least to me. Also a Conditional can be taken from a different lock all the time, unlike synchronized.
Other advantages are (unrelated here): you can create multiple Conditions, thus waking up only the thread you want; unlike notifyAll for example. Then there are methods with expiration, like awaitUntil(Date) or await(long, TimeUnit) or awaitNanos. There is even a method that will await and ignore interrupts , at all : awaitUninterruptibly.
That being said you don't need lock::unlock after await as the documentation is pretty clear in this regard:
The lock associated with this Condition is atomically released ...
An a lot more straightforward approach would be:
static class AsyncExecutor {
private static final ExecutorService service = Executors.newSingleThreadExecutor();
public static void execute(Runnable runnable) {
service.execute(runnable);
}
}
None of the above. The third is closest, but still not the best way to do it. Use a looper+handler, or a message queue. Also, there should be a message you can send to any thread to tell it to exit its loop and terminate. Otherwise you'll leak any memory it can reference (which is a lot since it will have an internal reference to its parent) when its no longer needed but sticks around for eternity anyway. Remember a thread is never GCed until it exits.

ReentrantLock condition wait get IllegalMonitorStateException in java

My application will keep monitoring a folder, once it is not empty, it will wake up the worker thread. IllegalMonitorStateException will be thrown in the wait .
what is the reason ?
import java.io.File;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.io.FileUtils;
public class LockTest {
public static void main(String[] args) {
String folder = "C:\\temp\\test";
final ReentrantLock messageArrivedLock = new ReentrantLock();
final Condition messageArrivedCondition = messageArrivedLock.newCondition();
Thread workerThread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("worker thread is running");
messageArrivedLock.lock();
while (true) {
System.out.println("worker thread is waiting");
try {
messageArrivedCondition.wait(); //Exception here
System.out.println("worker thread wakes up");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (messageArrivedLock.isHeldByCurrentThread()) {
messageArrivedLock.unlock();
}
}
}
}
});
workerThread.start();
while (true) {
long size = FileUtils.sizeOf(new File(folder));
System.out.println("size:" + size); // 1000
messageArrivedLock.lock();
try {
if (size > 0) {
messageArrivedCondition.signalAll();
}
} finally {
if (messageArrivedLock.isHeldByCurrentThread()) {
messageArrivedLock.unlock();
}
}
}
}
}
I'm going to assume you meant to invoke Condition#await, which will typically (as is the case here) have the same behavior you experienced with Object#wait.
The current thread is assumed to hold the lock associated with this
Condition when this method is called. It is up to the implementation
to determine if this is the case and if not, how to respond.
Typically, an exception will be thrown (such as
IllegalMonitorStateException) and the implementation must document
that fact.
Presumably your while loop iterated once, released the lock inside the finally. On its second iteration, your thread doesn't have the lock, so calling wait will throw the IllegalMonitorStateException. Your thread needs to own the lock to invoke await on the associated Condition.
You can acquire the lock within the while loop.

Stuck in wait() for thread execution to return

I'm trying to write a thread that I can delegate testing and evolution of a robot to while I sort the existing chromosomes by fitness in the main thread. Below is the initial fitness method. What I want to do here is to have each genome tested by a robotHandler as the tests are 30 - 40 seconds long. I will only be running one of these threads at any given time.
Currently I seem to get caught in the wait() section of the intialFitness method. This is my first attempt at multithreading so any help as to how to debug the problem or if someone can spot the issue that would be fantastic
The RobotInterface class is just a testing class at the moment, I have commented out the log4j and sleep declarations to try and rule these out (Incidentally log4j was not logging anything in the thread if that helps)
public synchronized ArrayList<Genome> initialFitness( ArrayList<Genome> population)
{
for ( int i = 0; i < population.size(); i++ )
{
candidateTest = new CandidateTest(population.get(i));
Thread robotHandler = new Thread(new RobotInterface( candidateTest));
while(! (candidateTest.finishedYet() ))
{
try
{
wait();
}
catch (InterruptedException e)
{
logger.debug("The initialFitness method was interrupted, this shouldn't happen");
}
}
population.set(i, candidateTest.getCandidate());
}
return population;
}
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.util.Random;
The RobotInterface Class
public class RobotInterface implements Runnable
{
// create a serial connection
// transmit a string and check for response
// wait for evaluation
// take evaluation
private CandidateTest candidate;
private Random rng = new Random();
//protected static Logger logger = Logger.getLogger("Thread" + Thread.currentThread().getName());
public RobotInterface(CandidateTest test)
{
this.candidate = test;
//PropertyConfigurator.configure("log4j.properties");
}
public void evaluate (Genome genome)
{
//send to robot and return fitness
genome.setFitness(rng.nextDouble());
//logger.debug("fitness is " + genome.getFitness());
try
{
//logger.debug("Thread sleeping for 4 seconds");
//Thread.sleep(4000);
}
catch(Exception E)
{
}
}
public void run()
{
//logger.debug("entering run of Robot Interface");
//logger.debug("Send Genome via serial and wait for a response");
Genome testSubject = candidate.getCandidate();
evaluate(testSubject);
candidate.finished();
notifyAll();
}
}
The CandidateTest Class
public class CandidateTest
{
private volatile Genome candidate;
private volatile boolean testFinished = false;
public CandidateTest(Genome g)
{
candidate = g;
}
public synchronized Genome getCandidate()
{
return candidate;
}
public synchronized void finished()
{
testFinished = true;
}
public synchronized boolean finishedYet()
{
return testFinished;
}
}
First, you are not starting the robotHandler thread. So your main thread gets to wait() and then no other thread ever comes along to notify it.
Second, you call wait() on whatever class initialFitness belongs to, but you call notifyAll() on RobotInterface. So RobotInterface will notify everyone who is waiting on it (nobody) and your main code will continue to wait. You need to call notifyAll() on the same object on which you called wait().
I suggest
synchronized(candidateTest) {
candidateTest.wait();
}
and
candidateTest.notify();
Never seen where the Thread is started. Try:
Thread robotHandler = new Thread(new RobotInterface( candidateTest)).start();
so your notifyAll() is never called
Nathanial hit the nail on the head but I would suggest using the java.util.concurrent package if you are just getting started with concurrency in Java. Found a nice beginners article on DZone for you: http://java.dzone.com/articles/lazy-developers-introduction

waiting Thread never wakes up

I have a ThreadManager with two Threads. One for gui-relevant requests and one for measurement-relevant requests. The are both running and checking their queue of requests, if there is any, they are processing the request. One can add requests at any time, using the static ThreadManager.addGuiRequest(eGuiRequest) and ThreadManager.addMeasRequest(eMeasRequest) methods. Now both of those need to be initialized which is done by adding a INIT request to the corresponding queue. But the initialization of the measurement is depending on the fact that the gui is already initialized. I tried to solve this using wait()/notify(), but I can not get it working.
Here is a SSCCE. At startup, both queues have a INIT request added and are then started. The measurement initialization detects that the gui is not yet initialized and perfomrs a wait(). The gui initializes (simulated by sleeping for 5s). This all works fine.
After the gui initialized, it tries to wake up the measurement thread, but the measurement thread does not wake up... I based my wait()/notify() code on this article. What is going wrong here?
import java.util.LinkedList;
import java.util.NoSuchElementException;
public class ThreadManager {
public static void main(String[] args) {
new ThreadManager();
ThreadManager.addMeasRequest(eMeasRequest.OTHER_STUFF);
}
public enum eGuiRequest { INIT, OTHER_STUFF; }
public enum eMeasRequest { INIT, OTHER_STUFF; }
private static LinkedList<eGuiRequest> guiQueue = new LinkedList<eGuiRequest>();
private static LinkedList<eMeasRequest> measQueue = new LinkedList<eMeasRequest>();
private static Thread guiThread, measThread;
protected boolean initialized = false;
public ThreadManager() {
final int waitMs = 200;
guiThread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
if (guiQueue.isEmpty()) sleepMs(waitMs);
else {
eGuiRequest req = guiQueue.getFirst();
processGuiRequest(req);
guiQueue.removeFirst();
}
} catch (NoSuchElementException e) {}
}
}
private void processGuiRequest(eGuiRequest req) {
System.out.println("T: " + "Processing Gui request: " + req);
switch (req) {
case INIT:
// do some initializiation here - replaced by a wait:
sleepMs(5000);
System.out.println("I: " + "guiThread finished, waking up measThread");
synchronized (measThread) {
initialized = true;
measThread.notify();
}
break;
case OTHER_STUFF:
// do other stuff
break;
}
}
});
measThread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
if (measQueue.isEmpty()) sleepMs(waitMs);
else {
eMeasRequest req = measQueue.getFirst();
processMeasurementRequest(req);
measQueue.removeFirst();
}
} catch (NoSuchElementException e) {}
}
}
private void processMeasurementRequest(eMeasRequest req) {
if (req == eMeasRequest.INIT) { // if init, wait until GUI is initialized
synchronized (this) {
while (!initialized) {
System.out.println("I: " + "measThread waits for guiThread to finish initializiation");
try {
wait();
} catch (Exception e) {}
System.out.println("I: " + "measThread awakes");
}
}
}
System.out.println("T: " + "Processing Measurement request: " + req);
// process request here:
sleepMs(5000);
}
});
addGuiRequest(eGuiRequest.INIT);
addMeasRequest(eMeasRequest.INIT);
guiThread.start();
measThread.start();
}
public static void sleepMs(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException ee) {}
}
public static void addGuiRequest(eGuiRequest req) {
guiQueue.add(req);
}
public static void addMeasRequest(eMeasRequest req) {
measQueue.add(req);
}
}
The GUI thread calls notify() on measThread (of type Thread), and the processMeasurementRequest() method calls wait() on this, which is the Runnable instance used by measThread.
I would advise using a specific object, shared by both threads to wait and notify:
private static final Object GUI_INITIALIZATION_MONITOR = new Object();
Also, instead of using a LinkedList and sleeping an aritrary time between requests, I would use a BlockingQueue: this would allow the consuming thread to handle a request as soon as there is one, and would avoid unnecessary wakeups from the sleeping state.
Also, instead of the low-level wait/notify, you could use a CountDownLatch initialized to 1. The GUI thread would countDown() the latch when it's initialized, and the mesurement thread would await() the latch until the GUI thread has called countDown(). This would delegate complex synchronization and notification stuff to a more high-level, well-tested object.
The main problem is that you call notify() on measThread, but wait() is called on an anonymous class. The easiest way to fix this is to create a special object for synchronization. For example, you create a field:
private static final Object LOCK = new Object();
Then you write synchronized blocks using this object and call its methods like this:
synchronized (LOCK) {
while (!initialized) LOCK.wait();
}
Also I have to say that this piece of code doesn't use any synchronization at all for the fields accessed from different threads, which means that it can break at any time. Both queues are accessed outside the threads created by you, this means that you should either access them with a lock held all the time, or you can make them thread safe by using a built-in synchronized list:
quiQueue = Collections.synchronizedList(new LinkedList<eGuiRequest>());
initialized is accessed from synchronized blocks, but right now they synchronize on different locks (I have described this problem at the start of my answer). If you fix this problem, initialized will also be working as it should.
Just do not sent init request to measurment at startup. Sent it from processGuiRequest() after execution of init gui request. Then no wait/notify stuff is needed.

Categories

Resources