Java同步对象?

3

我有一个Java类,用于读取UDP数据包并将其放入对象中(在基本无限循环中)。然后,在多个独立线程中访问此对象,但显然,由于同时填充它,所有这些getter/setter都在同步方法中。问题是,目前这些getter具有以下代码:

public synchronized SomeObject exampleGetter() {
    if(this.isReceiving)
        return oldCachedObject;
    else
        return currentObject;
}

显然,这并不是最好的做法,那么我该如何编写方法(很多不同的方法)来完全将对象锁定在一个线程上,并阻止其他线程(包括创建对象的线程)?我看了看同步块,但是我有点困惑“锁定对象”的效果是什么,那是在给定时间内访问该块的对象吗?任何建议都将不胜感激。谢谢!


3
请查看《Java并发编程实践》(http://jcip.net/)。 - ObscureRobot
1
谷歌搜索“Java中的生产者/消费者”。 - Amir Afghani
3个回答

5
synchronized 关键字会对整个对象实例进行同步,而不仅仅是针对 setter。我更愿意采用细粒度的锁策略,或者更好的方法是使用线程安全的数据结构来存储和获取接收到的数据。我个人很喜欢 BlockingQueue<T> ,其中 T 是你从网络上接收到的数据类型。

假设你正在通过套接字接收 Object

public class ReceivedDataHolder{
    BlockingQueue<Object> dataBuffer = new LinkedBlockingQueue<Object>();
    //...
    public void dataReceived(Object data){
       dataBuffer.offer(data);
    } 

    public Object getReceivedData(){
       return dataBuffer.take();
    }
}

当你接收到数据时,你可以在套接字中执行以下操作:

receivedDataHolder.dataReceived(object);

任何需要获取数据的线程都应该执行以下步骤:

receivedDataHolder.getReceivedData();

这种方法调用会阻塞调用线程,直到队列中有元素可用(有关更多详细信息,请查看此文档)。

我希望这可以帮到您。


2
BlockingQueue是一个接口,所以new BlockingQueue<Object>();无法编译通过。你必须使用实现该接口的具体类,比如ArrayBlockingQueue<T>或者LinkedBlockingQueue<T>,它们是最常用的生产者/消费者模式下的具体阻塞队列。 - Bruno Reis
@BrunoReis 确实,是我的一个小错误。现在已经修复了。 - GETah

2

0

Java中的所有对象都有一种称为内在锁的东西,如果任何线程想要对任何对象执行任何操作,则需要获取该对象的内在锁。这将确保在任何给定时间只有1个线程将处理您的代码块。

线程可以在任何对象上获取锁,如果该对象未被任何其他线程锁定,则该线程将等待,直到其他线程释放该对象上的锁。

如果您使用同步块,则代码将类似于此:

public void SomeObject exampleGetter() {

synchronized(this)
{


if(this.isReceiving)
        return oldCachedObject;
    else
        return currentObject;


}

在这种情况下,当您的线程进入同步块时,如果任何其他线程正在锁定此对象,则它将等待该线程释放锁。如果该对象是空闲的,则您的线程将获取该对象上的锁并执行操作,然后释放该对象上的锁。
有关同步块、方法和内部锁的更多信息,请参见http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html 希望对您有所帮助 :)

3
完全胡说八道:如果任何线程想要对任何对象执行任何操作,则需要获取该对象的内在锁定。任何线程都可以在不获取任何类型的锁定的情况下对其所知道的任何对象进行任何操作。 - Bruno Reis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接