I have a problem with a task. Namely, we must write a class, which is called from Threads. One of the methods is:
public static synchronized void waitForResults() {
}
So the Master-Thread calls this method, and then the Master-Thread triggers an other Thread, that new work is to be done. How can I tell the Master-Thread that he sleep, while the Worker-Thread works?
Using the wait() and the notify() mechanism. Every java object posses those methods. A mechanism block a thread until some condition is met.
For exampe, if your main thread calls another thread that will change the value of the result variable. Then, you could wait on the result until it gets notified by some other thread:
private static StringBuilder result= new StringBuilder();
public static void mainThreadWork() {
new WorkerThread().start();
synchronized (result) {
System.out.println(result.toString()); //prints ""
result.wait();
System.out.println(result.toString()); //prints "modified"
}
}
private static class WorkerThread extends Thread {
#Override
public void run() {
synchronized(result) {
result.append("modified");
result.notify();
}
}
}
What happens: when a thread calls a wait on some object, it yields a CPU to other Threads and (as the method name says) waits for another thread to send a notify signal on that thread. notify yields a CPU to the thread that was waiting on that object.
Some rules must be respected, for example, wait() and notify() must be invoked inside a synchronized block.
Since Java 1.5 there are more abstract levels of synchronization and wait-notify mechanisms, so you could check java's concurrent library. It offers you to lock and wait for the object on more abstract object-like level:
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
So instead of synchronized blocks and waits and notifies you could just:
public static void mainThreadWork() {
lock.lock();
new WorkerThread().start();
System.out.println(result.toString()); //prints ""
condition.await();
System.out.println(result.toString()); //prints "modified"
lock.unlock();
}
And in the WorkerThread:
#Override
public void run() {
lock.lock();
result.append("modified");
condition.singal();
lock.unlock();
}
Related
I'm trying to create thread safe queue in java. I've come across this example:
class ProducerConsumer<T> {
private static final int BUFFER_MAX_SIZE = 42;
private List<T> buffer = new LinkedList<>();
synchronized void produce(T value) throws InterruptedException {
while (buffer.size() == BUFFER_MAX_SIZE) {
wait();
}
buffer.add(value);
notify();
}
synchronized T consume() throws InterruptedException {
while (buffer.size() == 0) {
wait();
}
T result = buffer.remove(0);
notify();
return result;
}
}
I'm new to java. In my understanding those two 'synchronized' keywords would prevent contention inside each method, but not when both methods are called simultaneously. E.g. thread P calls produce, locks method, thread C calls consume, locks other method, then one tries to extract element from list, another tries to insert element, thread exception arises.
My question: Is this example broken?
Or maybe I'm missing something and it's ok.
JLS, §17.1 is quite explicit about the mechanism:
...
A synchronized method (§8.4.3.6) automatically performs a lock action when it is invoked; its body is not executed until the lock action has successfully completed. If the method is an instance method, it locks the monitor associated with the instance for which it was invoked (that is, the object that will be known as this during execution of the body of the method). If the method is static, it locks the monitor associated with the Class object that represents the class in which the method is defined. If execution of the method's body is ever completed, either normally or abruptly, an unlock action is automatically performed on that same monitor.
...
Thus, it is guaranteed that at one point in time on one object at most one thread is executing either produce(...) or consume(). It is not possible that, at one point in time, one thread executes produce(...) on an object while another thread executes consume() on the same object.
The call to wait() in consume() releases the intrinsic lock and blocks execution. The call to notify() in produce(...) notifies one wait()ing thread (if any), so it can fight for the lock as soon as the lock is released by the current owner. Notice that a call to notify() does not release the intrinsic lock. It just wakes up a wait()ing thread. This can be made observable with the following code snippet:
class Ideone {
private static final Object lock = new Object();
public static void main(String[] args) {
printWithThreadNamePrefix("Start");
Thread waiter = new Thread(Ideone::waiter);
waiter.start();
// Give waiter some time to a) start and b) acquire the intrinsic lock
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
final Thread notifier = new Thread(Ideone::notifier);
notifier.start();
while (true) {
try {
waiter.join();
break;
} catch (InterruptedException e) {
}
}
printWithThreadNamePrefix("End");
}
private static void waiter() {
synchronized (lock) {
printWithThreadNamePrefix("Waiting...");
while (true) {
try {
lock.wait();
break;
} catch (InterruptedException e) {
}
}
printWithThreadNamePrefix("... done waiting");
}
}
private static void printWithThreadNamePrefix(String msg) {
System.out.println(String.format(
"%s: %s",
Thread.currentThread().getName(),
msg));
}
private static void notifier() {
synchronized (lock) {
printWithThreadNamePrefix("notifying");
lock.notify();
while (true) {
}
}
}
}
Ideone demo
The program will never terminate. Although thread two calls notify(), it then enters an endless loop, never actually releasing the intrinsic lock. Thus, one never has a chance to acquire the intrinsic lock, and the program "hangs" (it is neither a deadlock, nor a livelock, it simply cannot proceed).
The things I recommend to change are:
declare private List<T> buffer additionally as final
call notifyAll() instead of notify() in order to wake all waiting threads (they will still execute sequentially, for details see this question by Sergey Mikhanov and its answers)
I was looking for a way to make one thread wait/sleep until another thread signalled that something was ready. The waiting thread should wake up, process the data that was made available, then go back to sleep until the other thread signalled again.
The simplest method I could find was Object.wait() and Object.notify(), which behaved like a semaphore initialised to value 0. However, without the synchronized statements around notify/wait, Java always threw IllegalMonitorStateException when the thread was not the monitor owner. So I simply put them around the code like shown below.
THREAD 1: running infinite loop
public class Main {
private Handler handler; // only one instance (singleton pattern)
public void listen() {
while (true) {
try {
synchronized (handler) {
handler.wait();
int value = handler.getSize();
// do something
}
} catch (InterruptedException e) {
// ...
}
}
}
}
THREAD 2: Some other class calls removeItem
public class Handler {
// SINGLETON PATTERN - ONLY ONE INSTANCE
private ArrayList<Integer> sharedList;
private Handler() {
sharedList = new ArrayList<>();
}
public void addItem(Integer i) {
synchronized (sharedList) {
// add to list
}
}
public void removeItem(int i) {
synchronized (sharedList) {
// remove item
// notify that something is removed
synchronized (this) {
this.notify(); // this == handler
}
}
}
public int getSize() {
synchronized (sharedList) {
return sharedList.size();
}
}
}
It seems to work perfectly fine but not sure if there is a hidden bug.
My question is: Is this safe? Does wait release the instance lock for handler/this so notify can acquire the lock?
Synchronized blocks are safe. The statement synchronized(obj) acquires the lock of the argument obj, so you can call wait and notify on it. They both require that the current thread holds the lock on the object.
You have to be careful about the double-locking you have in removeItem where you lock two objects. If you ever need this, you have to make sure that you always lock them in the same order, otherwise, you may create a deadlock.
i want to understand this:
String string;
public Test(String string){
this.string = string;
.....
}
public void foo(newObjectPerCall o) {
synchronized (o) {
//each thread can enter here because the object passed is always different
....
synchronized (string) {
// acquire this lock if the String is free.
}
}
}
public synchronized void function() {
}
public static void main(){
Test test = new Test("hello");
for(int i = 0; i < 10;i++){
WorkerThread workerThread = new WorkerThread(test);
workerThread.start();
}
}
thread class
public class WorkerThread extends Thread {
private Test test;
public WorkerThread(Test test) {
this.test = test;
}
#Override
public void run() {
while (true) {
test.foo(new Object());
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.function();
}
}
}
my doubts are:
if one thread acquire the inner lock, other threads that acquired the outer lock, will remains inside the foo function?
When on thread ,for some reasons, remains outside the foo function, can this one acquire the lock of test instance inside function?
if one thread acquire the inner lock, other threads that acquired the outer lock, will remains inside the foo function?
Yes. They will block, waiting to acquire the monitor for string.
When on thread ,for some reasons, remains outside the foo function, can this one acquire the lock of test instance inside function?
Yes, it's entirely independent of the other monitors. A synchronized instance method is just equivalent to one whose body is
synchronized (this) {
...
}
If no other thread already owns the monitor for this, the "new" thread can acquire it regardless of what other monitors are owned. But as all your worker threads are using the same instance of Test, only one of them will be able to be "in" function() at a time. That can be at the same time as another thread is executing foo() though.
Sorry I know only the answer only for the first question
if one thread acquire the inner lock, other threads that acquired the outer lock, will remains inside the foo function?
Yes
Here I have an object with 2 threads and providing lock on object by print() but after some loop it losing lock and execute the second thread and it will change the value of breakLoop and first thread will be terminate.
public class ThreadLock {
public static void main(String[] args) {
Entity entity=new Entity();
RunnableClass runnable = new RunnableClass(entity);
Thread threadClass= new Thread(runnable);
Thread threadClass2= new Thread(runnable);
threadClass.setName("First Thread");
threadClass2.setName("Second Thread");
threadClass.start();
threadClass2.start();
}
}
class RunnableClass implements Runnable{
Entity entity;
public RunnableClass(Entity entity) {
this.entity=entity;
}
public void run(){
if(Thread.currentThread().getName().equalsIgnoreCase("First Thread"))
entity.print();
else{
entity.print("");
}
}
}
class Entity{
public void print(String str){
System.out.println("Non sysncronized method accessed by "+Thread.currentThread().getName());
breakLoop=false;
}
boolean breakLoop=true;
//lock will work for same object
public synchronized void print(){
System.out.println("Lock aquired by : "+Thread.currentThread().getName());
while (breakLoop) {
System.out.println("hhhhhhhhhhhhhh");
}
System.out.println("Lock released by : "+Thread.currentThread().getName());
}
}
The first thread having the lock doesn't stop the second thread from calling the Entity.print(String) method, because that method doesn't try to acquire the lock. Calling print(String) sets the breakLoop flag to false.
(When the flag value becomes visible to the other thread is not well-defined due to memory visibility issues --it would be better to make the breakLoop instance variable volatile-- but that doesn't necessarily mean the second thread will never see the change to the instance variable. Memory visibility issues are more apparent on some platforms than others.)
If you change the print(String) method to be synchronized, it will hang waiting for the first thread to finish.
In Java, if a synchronized method contains a call to a non-synchronized, can another method still access the non-synchronized method at the same time? Basically what I'm asking is everything in the synchronized method have a lock on it (including calls to other synchronized methods)?
If a synchronized method calls another non-synchronized method, is there a lock on the non-synchronized method
The answer depends on the context.
If you are in a synchronized method for an object, then calls by other threads to other methods of the same object instance that are also synchronized are locked. However calls by other threads to non-synchronized methods are not locked – anyone can call them at the same time.
public synchronized void someSynchronizedMethod() {
...
someNonSynchronizedMethod();
...
}
// anyone can call this method even if the someSynchronizedMethod() method has
// been called and the lock has been locked
public void someNonSynchronizedMethod() {
...
}
Also, if you call someSynchronizedMethod() but happen to be within the someNonSynchronizedMethod() method, you still hold the lock. The lock is enabled when you enter a synchronized method (or block) and is disabled when you exit that method. You can call all sorts of other unsynchronized methods and they will still be locked.
But you are asking two different things in your question:
In Java, if a synchronized method contains a call to a non-synchronized, can another method still access the non-synchronized method at the same time?
Yes. Other methods can access non-synchronized methods.
Basically what I'm asking is everything in the synchronized method have a lock on it (including calls to other synchronized methods)?
Uh, yes. Other calls to synchronized methods are locked. But non-synchronized methods are not locked.
Also, remember that if the method is static then the lock is on the Class object in the ClassLoader.
// this locks on the Class object in the ClassLoader
public static synchronized void someStaticMethod() {
If the method is an instance method then the lock is on the instance of the class.
// this locks on the instance object that contains the method
public synchronized void someInstanceMethod() {
There are 2 different locks in those 2 cases.
Lastly, when you are dealing with synchronized instance methods, each instance of the class is what is locked. This means that two threads could be in the same synchronized method at the same time with different instances. But if 2 threads try to operate on synchronized methods on the same instance, one will block until the other one exits the method.
If thread A calls synchronized method M1 which in turn calls unsynchronized method M2, then thread B can still call M2 without blocking.
Synchronized method acquires and releases intrinsic lock on the object on which it is called. This is why it may block. Unsynchronized method doesn't attempt to acquire any lock (unless it is done explicitly in the code).
Thus, if you need to ensure mutual exclusion for M2 as well, you should make it synchronized regardless of whether its callers (like M1) are synchronized or not.
The lock doesn't belong to the thread. The lock actually belongs to the object(or Class in case of Class level lock), and a thread acquires lock on the Object(or Class in case of Class level lock) within a synchronized context.
Now, there is no lock propagation in java as it is discussed above. Here is a small demo:
public class TestThread {
/**
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ThreadCreator1 threadCreator1 = new ThreadCreator1();
ThreadCreator2 threadCreator2 = new ThreadCreator2();
Thread t1 = new Thread(threadCreator1,"Thread 1");
Thread t3 = new Thread(threadCreator1,"Thread 3");
Thread t2 = new Thread(threadCreator2,"Thread 2");
t1.start();
Thread.sleep(2000);
t3.start();
}
}
public class ThreadCreator1 implements Runnable {
private static final Task task= new Task();
private static final Task2 task2= new Task2();
#Override
public void run() {
try {
if(Thread.currentThread().getName().equals("Thread 1"))
task.startTask2(task2);
if(Thread.currentThread().getName().equals("Thread 3"))
task2.startTask();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
/**/
}
}
public class Task {
public static final Task task = new Task();
public static List<String> dataList = new ArrayList<String>();
ReentrantLock lock = new ReentrantLock();
public void startTask2(Task2 task2) throws InterruptedException
{
try{
lock.lock();
//new Task2().startTask();
task2.startTask();
}
catch(Exception e)
{
}
finally{
lock.unlock();
}
}
}
public class Task2 {
ReentrantLock lock = new ReentrantLock();
public void startTask() throws InterruptedException
{
try{
//lock.lock();
for(int i =0 ;i< 10;i++)
{
System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName());
Thread.sleep(1000);
}
}
catch(Exception e)
{
}
/*finally
{
lock.unlock();
}*/
}
}
Just I have used Reentrant lock here.
If the above code is run, then there will be interleaving between thread 1 and thread 3, but if the lock portion of Task2 class is uncommented, then there will be no interleaving and the thread which acquire the lock first will complete fully first, then it will release the lock and then the other thread can carry on.
The lock belongs to the thread, not to the method (or more precisely, its stack frame). It just so happens that if you have a synchronized method, you're guaranteed that the thread will own the lock before the body of the method start, and will release it afterwards.
Another thread can still invoke the second, non-synchronized method. An unsynchronized method can be called by any thread at any time.