简体   繁体   中英

Understanding synchronized method in JAVA

I am new to JAVA and learning multithreading in JAVA. This is my code snippet.

import java.util.*;
import java.lang.*;
import java.io.*;

class Manager {
    static final int MAXQUEUE = 5;
    private Vector messages = new Vector();

    public synchronized void putMessage() throws InterruptedException {
        while (messages.size() == MAXQUEUE) {
            System.out.println("waiting for space in queue ");
            wait();
        }
        messages.addElement(new java.util.Date().toString());
        System.out.println("created a new message and message count is " + messages.size());
        notify();
    }

    public synchronized String getMessage() throws InterruptedException {
        notify();
        while (messages.size() == 0) {
            System.out.println("queue is empty ");
            wait();
        }
        String message = (String) messages.firstElement();
        messages.removeElement(message);
        System.out.println("removed a message and message count is " + messages.size());
        return message;
    }
}

class Producer extends Thread {
    Manager myRef;

    Producer(Manager ref) {
        myRef = ref;
    }

    public void run() {
        try {
            while (true) {
                myRef.putMessage();
                sleep(1000);
            }
        } catch (InterruptedException e) {
        }
    }
}

class Consumer extends Thread {
    Manager myRef;

    Consumer(Manager ref) {
        myRef = ref;
    }

    public void run() {
        try {
            while (true) {
                String message = myRef.getMessage();
                System.out.println("Got message: " + message);
                sleep(2000);
            }
        } catch (InterruptedException e) {
        }
    }

    public static void main(String args[]) {
        Manager ref = new Manager();
        Producer producer = new Producer(ref);
        producer.start();
        new Consumer(ref).start();
    }
}

What i am expecting :

  1. First my Producer thread will take control of the lock on Manager object. It will call putMessage() until the count is 5 and will release the lock.
  2. Now Consumer thread will take the lock and start reading the message until the list is empty and then it will release the lock. This sequence will continue.

But, what is happening :

created a new message and message count is 1
removed a message and message count is 0
Got message: Thu Aug 13 07:26:45 GMT 2015
created a new message and message count is 1
removed a message and message count is 0
Got message: Thu Aug 13 07:26:46 GMT 2015
and so on.....

As you can see, my consumer thread is able to call readMessage() even though the lock of the manager object is with Producer thread which is executing putMessage(). If one thread is executing an instance method, how other thread is able to call the other instance method?

Please correct my understanding.

First your producer Thread executes the putMessage method. He creates one item and adds it to the messages list. When putMessage is finished and one item was created, the producer thread goes to sleep.

When the consumer thread awakes he is free to access the getMessage method and consumes the only item. Then consumer goes to sleep.

This process repeates all the time. As you expected the synchronized keyword prevents that any synchronized methods of one object can be executed in parallel. And as I explaind that isn't happening. The threads just alternate in accessing the methods. With every method call just one item is produced or consumed.

This is the correct behaviour of java multithreading.

First my Producer thread will take control of the lock on Manager object. It will call putMessage() until the count is 5 and will release the lock.

I am not sure if you have written code for this line

 It will call putMessage() until the count is 5 and will release the lock.

Because your code says

     public synchronized void putMessage() throws InterruptedException {
        // Check if messages list size is full. If full then wait for emptying
        while (messages.size() == MAXQUEUE) {
            System.out.println("waiting for space in queue ");
            wait();
        }
       // If not, add one element. Where have you written code for adding 5   elements at once. 
       messages.addElement(new java.util.Date().toString());
       System.out.println("created a new message and message count is " +   messages.size());
      notify();
    }

Please check below link.

https://community.oracle.com/thread/2293851

Step wise execution of each thread:

  1. Producer thread starts:

    run() method is called which calls putMessage method

    putMessage(): It is synchronized and hence the current thread which is the producer thread acquires lock on the current Manager object. Now during this time no other thread can call another synchronized method on the same object. As the messages's size is < MAXQUEUE(5), since it is just the first insertion it proceeds on to insert an element into the vector message. Then it calls notify() to signal any other waiting thread to be ready to re-obtain the lock. It is important to note that calling notify() in itself does not release the lock. You can continue to do stuff after calling notify() if you desire. Notify() is just a signal for the waiting threads to get ready to queue up to acquire the lock. Lock is released only if the synchronized function exits or it calls wait().

    thread sleeps for 1 second.

  2. Consumer thread starts:

    run() method is called which calls getMessage()

    getMessage(): As explained above, it will work on similar principle to extract a message from the vector if it is not empty. Notice that it calls notify() first when it enters. This is done in order to signal any waiting producer thread to get ready as after getMessage's execution it is guaranteed that the vector's size will be less than MAXSIZE. Again as stated earlier, simply calling notify() does not release the lock.

    thread sleeps for 2 second.

These two threads execute in a parallel fashion, and as you sleep consumer for twice as long as the producer, you will notice after sometime that the buffer will get filled and it is then, when we actually require the wait and notify methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM