我在java中有一个类,它读取UDP数据包并将它们放在一个对象中(基本上是无限循环)。然后在多个单独的线程中访问此对象,但显然,由于它是同时填充的,因此所有这些getter / setter都采用同步方法。问题是,现在这些getter有这样的代码:
public synchronized SomeObject exampleGetter() {
if(this.isReceiving)
return oldCachedObject;
else
return currentObject;
}
显然,这不是最好的做事方式,所以我应该如何编写方法(许多不同的方法),将对象完全锁定到一个线程并阻塞其他线程(包括创建的线程)首先是对象)?我看了一下synchronized块,但是我对于“锁定对象”有什么影响感到困惑,是那个在给定时间可以访问块的对象?任何意见,将不胜感激。谢谢!
答案 0 :(得分: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();
后一个方法调用将阻塞调用线程,直到队列中有一个元素可用(检查this以获取更多详细信息)
我希望这会有所帮助
答案 1 :(得分:2)
答案 2 :(得分:0)
java中的所有对象都有一些称为内部锁的东西,如果任何线程想对任何对象进行任何操作,那么它需要获取该对象的内部锁。它将保证在任何给定时间只有一个线程处理您的代码块。
一个线程可以获取对任何对象的锁定,如果该对象没有被任何其他线程锁定,如果它被锁定,那么该线程将等到另一个线程释放该对象的锁定。
如果您使用synchronized块,您的代码将有点像这样
public void SomeObject exampleGetter() {
synchronized(this)
{
if(this.isReceiving)
return oldCachedObject;
else
return currentObject;
}
在这种情况下,当你的线程进入同步块时,如果任何其他线程对此对象有锁定,那么它将等待该线程释放锁定。如果该对象是空闲的,那么你的线程将获得对该对象的锁定并执行操作,然后释放该对象的锁定。
有关同步块,方法和内部锁的更多信息,请参阅 http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
我希望它能帮到你:)。