对象锁定私有类成员 - 最佳实践? (Java) [英] Object locking private class members - best practice? (Java)

查看:175
本文介绍了对象锁定私有类成员 - 最佳实践? (Java)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在其他日子问了一个类似问题,但不满意响应,主要是因为我提供的代码有一些人们关注的问题。



基本上,在Java中锁定私有成员的最佳实践是什么?假设每个私有字段只能在孤立的情况下操作,而不能在一起操作(像在下面的Test类示例中),应该直接锁定每个私有字段(示例1),或者应该使用一个通用锁定对象, (示例2)



p> class Test {
private final List< Object> xList = new ArrayList< Object>();
private final List< Object> yList = new ArrayList< Object>();

/ * xList方法* /

public void addToX(Object o){
synchronized(xList){
xList.add(o);
}
}

public void removeFromX(Object o){
synchronized(xList){
xList.remove(o);
}
}

/ * yList方法* /

public void addToY(Object o){
synchronized(yList){
yList.add(o);
}
}

public void removeFromY(Object o){
synchronized(yList){
yList.remove(o);
}
}
}

示例2:每个私有字段使用锁定对象

  class Test {
private final Object xLock = new Object ;
private final Object yLock = new Object();
private List< Object> xList = new ArrayList< Object>();
private List< Object> yList = new ArrayList< Object>();

/ * xList方法* /

public void addToX(Object o){
synchronized(xLock){
xList.add(o);
}
}

public void removeFromX(Object o){
synchronized(xLock){
xList.remove(o);
}
}

/ * yList方法* /

public void addToY(Object o){
synchronized(yLock){
yList.add(o);
}
}

public void removeFromY(Object o){
synchronized(yLock){
yList.remove(o);
}
}
}


解决方案>

我个人喜欢第二种形式。没有其他代码可以使用该引用(禁止反射,调试API等)。您不需要担心列表的内部详细信息是否尝试在其上同步。 (你在列表上调用的任何方法显然都可以访问 this ,所以可以在它上面同步。)你只是 所以你也分开了我是锁和我是一个列表之间的关注。



我发现这样更容易推理



您可能希望创建一个单独的类,纯粹用作监视器,具有 toString()的覆盖,这有助于诊断。



不可否认,这种方法需要更多的内存,通常 你不需要担心代码锁定在 this ...但我个人觉得分离的关注的好处,而不必担心是否该代码 锁定自身超过效率成本。如果您发现浪费的对象是由于某种原因(并且在分析了您可能会遇到的类中的代码之后)而导致性能瓶颈,您可以随时选择使用第一种形式)。



(我个人希望Java和.NET 都没有按照每个对象都有一个关联的监视器路线,但这是一个不同的日子。)


I asked a similar question the other day but wasn't satisfied with the response, mainly because the code I supplied had some issues that people focused on.

Basically, what is the best practice for locking private members in Java? Assuming each private field can only be manipulated in isolation and never together (like in my Test class example below), should you lock each private field directly (example 1), or should you use a general lock object per private field you wish to lock (example 2)?

Example 1: Lock private fields directly

class Test {
  private final List<Object> xList = new ArrayList<Object>();
  private final List<Object> yList = new ArrayList<Object>();

  /* xList methods */ 

  public void addToX(Object o) {
    synchronized(xList) {
      xList.add(o);
    }
  }

  public void removeFromX(Object o) {
    synchronized(xList) {
      xList.remove(o);
    }
  }

  /* yList methods */ 

  public void addToY(Object o) {
    synchronized(yList) {
      yList.add(o);
    }
  }

  public void removeFromY(Object o) {
    synchronized(yList) {
      yList.remove(o);
    }
  }
}

Example 2: Use lock objects per private field

class Test {
  private final Object xLock = new Object();
  private final Object yLock = new Object();
  private List<Object> xList = new ArrayList<Object>();
  private List<Object> yList = new ArrayList<Object>();

  /* xList methods */ 

  public void addToX(Object o) {
    synchronized(xLock) {
      xList.add(o);
    }
  }

  public void removeFromX(Object o) {
    synchronized(xLock) {
      xList.remove(o);
    }
  }

  /* yList methods */ 

  public void addToY(Object o) {
    synchronized(yLock) {
      yList.add(o);
    }
  }

  public void removeFromY(Object o) {
    synchronized(yLock) {
      yList.remove(o);
    }
  }
}

解决方案

Personally I prefer the second form. No other code at all can use that reference (barring reflection, debugging APIs etc). You don't need to worry about whether the internal details of the list tries to synchronize on it. (Any method you call on a list obviously has access to this, so could synchronize on it.) You're purely using it for locking - so you've also got separation of concerns between "I'm a lock" and "I'm a list".

I find that way it's easier to reason about the monitor, as you can easily see all the possible code that uses it.

You may wish to create a separate class purely for use as monitors, with an override for toString() which could help with diagnostics. It would also make the purpose of the variable clearer.

Admittedly this approach does take more memory, and usually you don't need to worry about code locking on this... but I personally feel that the benefit of separating the concerns and not having to worry about whether that code does lock on itself outweighs the efficiency cost. You can always choose to go for the first form if you find that the "wasted" objects are a performance bottleneck for some reason (and after you've analyzed the code in the class you're potentially going to synchronize on).

(Personally I wish that both Java and .NET hadn't gone down the "every object has an associated monitor" route, but that's a rant for a different day.)

这篇关于对象锁定私有类成员 - 最佳实践? (Java)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆