了解JAVA中的同步方法

时间:2015-08-13 07:50:37

标签: java multithreading

我是JAVA的新手,在JAVA学习多线程。这是我的代码段。

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();
    }
}

我的期待

  1. 首先,我的Producer线程将控制Manager对象的锁定。它将调用putMessage()直到count为5并释放锁。
  2. 现在,Consumer线程将获取锁定并开始读取消息,直到列表为空,然后它将释放锁定。 此序列将继续。
  3. 但是,发生了什么

    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.....
    

    正如您所看到的,我的消费者线程能够调用readMessage(),即使manager对象的锁定与执行putMessage()的Producer线程有关。如果一个线程正在执行实例方法,其他线程如何能够调用另一个实例方法?

    请纠正我的理解。

3 个答案:

答案 0 :(得分:2)

首先,您的生产者Thread执行putMessage方法。他创建了一个项目并将其添加到messages列表中。当putMessage完成并创建了一个项目时,生产者线程将进入休眠状态。

当消费者线程醒来时,他可以自由访问getMessage方法并使用唯一的项目。然后消费者进入睡眠状态。

此过程始终重复。正如您所期望的那样,synchronized关键字可以防止一个对象的任何同步方法可以并行执行。正如我解释的那样,并没有发生。线程只是在访问方法时交替使用。每个方法调用只生成或消耗一个项目。

答案 1 :(得分:2)

这是java多线程的正确行为。

  

首先,我的Producer线程将控制Manager上的锁定   宾语。它将调用putMessage()直到count为5并且将会   释放锁。

我不确定您是否为此行编写了代码

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

因为您的代码显示

     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();
    }

请查看以下链接。

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

答案 2 :(得分:1)

逐步执行每个线程:

  1. 生产者线程开始:

    调用

    run()方法调用putMessage方法

    putMessage():它是同步的,因此作为生产者线程的当前线程获取当前Manager对象的锁定。现在,在此期间,没有其他线程可以在同一对象上调用另一个同步方法。由于消息的大小是< MAXQUEUE(5),因为它只是第一次插入,它继续将一个元素插入到矢量消息中。然后它调用notify()来指示任何其他等待线程准备好重新获得锁。重要的是要注意,调用notify()本身不会释放锁。如果您愿意,可以在调用notify()之后继续执行操作。 Notify()只是等待线程准备好排队获取锁的信号。仅当同步函数退出或调用wait()时才会释放锁。

    线程休眠1秒钟。

  2. 消费者线程开始:

    调用

    run()方法调用getMessage()

    getMessage():如上所述,它将以类似的原理工作,如果它不为空,则从向量中提取消息。请注意,它在进入时首先调用notify()。这样做是为了通知任何等待的生产者线程准备就绪,因为在getMessage执行之后它保证了向量的大小将小于MAXSIZE。再次如前所述,简单地调用notify()不会释放锁。

    线程睡2秒钟。

  3. 这两个线程以并行方式执行,当你让使用者睡眠时间是生产者的两倍时,你会注意到缓冲区将在某个时候被填充,然后,当我们实际需要wait和notify方法时