首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解JAVA中的同步方法

理解JAVA中的同步方法
EN

Stack Overflow用户
提问于 2015-08-13 07:50:36
回答 3查看 473关注 0票数 2

我对JAVA和学习JAVA多线程都很陌生。这是我的代码片段。

代码语言:javascript
复制
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. 首先,我的生产者线程将控制Manager对象上的锁。它将调用putMessage(),直到计数为5,并释放锁。
  2. 现在,使用者线程将获取锁并开始读取消息,直到列表为空,然后它将释放锁。这个序列还会继续。

但是,正在发生什么

代码语言:javascript
复制
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()的生产者线程。如果一个线程正在执行一个实例方法,那么其他线程如何能够调用另一个实例方法呢?

请纠正我的理解。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-13 11:27:57

每个线程的分步执行:

  1. 生产者线程启动: 调用run()方法,它调用putMessage方法 putMessage():它是同步的,因此当前线程(即生产者线程)获取当前Manager对象的锁。在此期间,没有其他线程可以在同一个对象上调用另一个同步方法。由于消息的大小< MAXQUEUE(5),因为它只是第一个插入到向量消息中的元素。然后,它调用通知(),以指示任何其他等待线程准备重新获得锁。重要的是要注意,调用notify()本身并不会释放锁。如果你想要的话,你可以在调用通知()之后继续做一些事情。通知()只是等待线程准备排队获取锁的一个信号。只有当同步函数退出或调用wait()时,锁才会释放。 线程休眠1秒。
  2. 消费者线程启动: 调用run()方法,它调用getMessage() getMessage():如上所述,如果消息不是空的,它将按照类似的原则从向量中提取消息。注意,它在进入时首先调用通知()。这样做是为了让等待的生产者线程做好准备,因为在getMessage执行之后,可以保证向量的大小小于MAXSIZE。同样,如前所述,简单地调用()并不会释放锁。 线程休眠2秒。

这两个线程以并行方式执行,当您睡眠使用者的时间是生产者的两倍时,您将在某个时候注意到缓冲区将被填充,这时我们实际上需要等待和通知方法。

票数 1
EN

Stack Overflow用户

发布于 2015-08-13 08:06:08

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

当使用者线程醒来时,他可以自由地访问getMessage方法并使用唯一的项。然后消费者就睡着了。

这个过程一直在重复。正如您所预期的,同步关键字阻止可以并行执行一个对象的任何同步方法。就像我解释的那样,这是不可能的。线程只是交替地访问方法。对于每个方法调用,只有一个项目被生产或消费。

票数 2
EN

Stack Overflow用户

发布于 2015-08-13 08:14:11

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

首先,我的生产者线程将控制Manager对象上的锁。它将调用putMessage(),直到计数为5,并释放锁。

我不确定您是否为这一行编写了代码。

代码语言:javascript
复制
 It will call putMessage() until the count is 5 and will release the lock.

因为你的代码说

代码语言:javascript
复制
     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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31982478

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档