Вопрос

I am trying to understand the use of Synchronized block.

In the below program, Inside a produce and consumer method I have created a synchronized block and if I lock it by using lock1(object). I am getting the following error, why is this, why am i getting this error?

I am aware that by replacing lock1 by this(same class). I can get rid of the error. I still want to know why this error as everything seems very logical to me.

Program

import java.util.Scanner;

public class Worker {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void produce() throws InterruptedException {

        synchronized (lock1) {
            System.out.println("Producer thread running");
            wait();
            System.out.println("Producer resumed");
        }
    }

    public void consumer() throws InterruptedException {
        Scanner scanner = new Scanner(System.in);
        Thread.sleep(2000);
        synchronized (lock1) {
            System.out.println("Waiting for return key");
            scanner.nextLine();
            System.out.println("return key is pressed");
            notify();
            Thread.sleep(5000);

            System.out.println("Consumer is over");
        }
    }

    public void main() {

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:503)
    at Worker.produce(Worker.java:14)
    at Worker$1.run(Worker.java:43)
    at java.lang.Thread.run(Unknown Source)
Это было полезно?

Решение

synchronized (lock1) {
    System.out.println("Producer thread running");
    wait();
    System.out.println("Producer resumed");
}

You acquire the monitor of lock1 and then proceed to wait on this which fails because, as the documentation of Object#wait states,

The current thread must own this object's monitor.

Другие советы

You need to call lock1.wait() and lock1.notify(). You can only call wait() or notify() on an object on which you hold the lock (lock1 in this case).

In the synchronized block the current thread is the owner of the synchronization object's monitor. In your case it is lock1.

According to the javadoc of Object.wait()

The current thread must own this object's monitor.

and Object.notify()

This method should only be called by a thread that is the owner of this object's monitor.

you must change your code to

synchronized (lock1) {
    System.out.println("Producer thread running");
    lock1.wait();
    System.out.println("Producer resumed");
}

and

synchronized (lock1) {
    System.out.println("Waiting for return key");
    scanner.nextLine();
    System.out.println("return key is pressed");
    lock1.notify();
    Thread.sleep(5000);

    System.out.println("Consumer is over");

}

To call wait() and notify() you need to own the object's monitor you want to call these two methods.

Link to javadoc Object.wait()

Citation from above link:

The current thread must own this object's monitor.

I am showing how I fixed the producer-consumer problem. I have using different way then you. I think this will help you..

And the to make any block or method synchronized their are some condition :

synchronized methods prevent more than one thread from accessing an object's critical method code simultaneously.

You can use the synchronized keyword as a method modifier, or to start a synchronized block of code.

To synchronize a block of code (in other words, a scope smaller than the whole method), you must specify an argument that is the object whose lock you want to synchronize on.

While only one thread can be accessing synchronized code of a particular instance, multiple threads can still access the same object's unsynchronized code.

static methods can be synchronized, using the lock from the java.lang.Class instance representing that class.

All three methods—wait(), notify(), and notifyAll()—must be called from within a synchronized context! A thread invokes wait() or notify() on a particular object, and the thread must currently hold the lock on that object.

class P implements Runnable{

    Data d;
    P(Data d){
        this.d = d;
        new Thread(this,"Producer").start();
    }

    public void run(){
        for(int i=0; i<=20; i++){
            d.set(i);
            System.out.println("put -> "+i);
        }
    }   
}

class C implements Runnable{

    Data d;
    C(Data d){
        this.d = d;
        new Thread(this,"Consumer").start();
    }

    public void run(){
        for(int i=0; i<=20; i++){
            int n = d.get();
            System.out.println("get -> "+n);
        }
    }

}

class Data{
    int n;
    boolean valueset=false;

    synchronized void set(int n){
        if(valueset){
            try{
                wait();
            }catch(Exception e){
                System.out.println("set -> Exception "+e);
            }
        }
        this.n = n ;
        valueset=true;
        notify();
    }

    synchronized int get(){
        if(!valueset){
            try{
                wait();
            }catch(Exception e){
                System.out.println("get -> Exception "+e);
            }
        }
        valueset=false;
        notify();
        return n ;
    }

}

class PC{
    public static void main(String[] args){
        Data d = new Data();
        new P(d);
        new C(d);
    }

}

You can download solution of producer consumer from here :

https://www.mediafire.com/?52sa1k26udpxveu

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top