【问题标题】:Threading issue..inner class..field线程问题..内部类..字段
【发布时间】:2012-07-25 12:54:48
【问题描述】:

我遇到线程问题..

我正在使用内部类进行查找..我一直在阅读有关如何正确执行此操作的内容,并且所有内容都指向使用字段..在我的情况下为“布尔验证”。

基本上如果对象在那里。我将字段声明为 true 并返回值。问题是,在性能测试期间,同一对象中的同一方法同时在多个线程中被调用,并且效果很有趣。 (我猜是因为 pause() (等待 10 毫秒))

所以在线程 A.. 那里的对象,所以它声明字段 true.. 等待 10 毫秒.. 在线程 B 中,对象不存在,但由于等待并且正在访问相同的字段,它无论如何都会返回 true。

我在这里遇到了麻烦:(

有人知道更好的方法吗?

boolean verify; 
  public boolean lookupAndVerify(String id) throws InterruptedException
  {
    final String key = id;
    PastryIdFactory localFactory = new rice.pastry.commonapi.PastryIdFactory(env);
    final Id lookupKey = localFactory.buildId(key);
    Past p = (Past) apps.get(env.getRandomSource().nextInt(apps.size()));
    p.lookup(lookupKey, new Continuation<PastContent, Exception>()
    {
      public void receiveResult(PastContent result)
      {
        P2PPKIContent content = (P2PPKIContent) result;
        if(content !=null){
        verify = true; 
        }
      }
      public void receiveException(Exception result)
      {
        System.out.println("Error looking up " + lookupKey);
      }
    });
    pause();
    return verify;
  }

【问题讨论】:

  • 在回读这个问题时只是在想自己。也许我应该创建一个访问器对象。每次调用lookupAndVerify() 时我都会创建一个新的。这样每次查找只会有一个新对象,线程不应该受到影响?
  • 我不太确定您在这里尝试做什么,看来您正在使用匿名内部类作为某种侦听器。这段代码看起来很乱,你想做什么?制作一个阻止执行的方法,直到线程收到一些结果?匿名内部类绝对不是要走的路。特别是在多线程环境中。如果结果准备好处理,您可以使用线程进行接收并通知其他线程。
  • @Conor:如果您实际上是在谈论使用具有set 方法的包装器,这将起作用,但您仍然遇到pause() 是一个糟糕的同步机制的问题.理想情况下,包装器还允许您在设置值之前阻塞,这就是Future&lt;T&gt;(和我的答案)的用武之地。
  • p.lookup 是免费糕点 API 的一部分。据我所知,这是进行查找的唯一方法。看看例子,人们似乎就是这样。
  • @MarkPeters 是的,马克你的建议很有意义。这是我第一次将线程作为主要问题进行性能测试。我不确定如何实现异步调用

标签: java thread-safety field inner-classes performance-testing


【解决方案1】:

我认为您可以对异步调用进行一些研究。暂停一定的毫秒数不是确保你的回调被调用的安全方法,正如你所说,如果对象由多个线程共享,则将 verify 设为字段将不起作用.

您可以使用的一个选项是 Future&lt;Boolean&gt;(在这种情况下,来自 Guava 库的 SettableFuture&lt;Boolean&gt; 很方便):

final SettableFuture<Boolean> verify = new SettableFuture<Boolean>();

p.lookup(lookupKey, new Continuation<PastContent, Exception>()
{
  public void receiveResult(PastContent result)
  {
    P2PPKIContent content = (P2PPKIContent) result;
    if(content !=null){
       verify.set(true);
    }
  }
  public void receiveException(Exception result)
  {
    System.out.println("Error looking up " + lookupKey);
    verify.set(false);
  }
});

return verificationQueue.get(); //this will block until verify has been set!

Future&lt;T&gt; 是一个并发构造,在未来的某个时间会有一个值。但是,只要您要求它的值,它就会阻塞,直到它有值为止。

编辑

如果由于某种原因你不能拉入 Guava,一个稍微不太直观的解决方案是使用容量为 1 的BlockingQueue&lt;Boolean&gt;:

final BlockingQueue<Boolean> verificationQueue = new ArrayBlockingQueue<Boolean>(1);

p.lookup(lookupKey, new Continuation<PastContent, Exception>()
{
  public void receiveResult(PastContent result)
  {
    P2PPKIContent content = (P2PPKIContent) result;
    if(content !=null){
       verificationQueue.put(true);
    }
  }
  public void receiveException(Exception result)
  {
    System.out.println("Error looking up " + lookupKey);
    verificationQueue.put(false);
  }
});

return verify.take(); //blocks until an item has been put on the queue

如果您要这样做,值得将队列封装在一个具有更可读 API 的类中。

【讨论】:

  • 太好了..谢谢..我用数组尝试了类似的东西..但很快发现这不是一个好方法..我会开始工作..非常感谢跨度>
  • 万一有人读到这个……我对马克列出的第一种方法有点困难……第二种方法马上就完美了……非常感谢@Mark对我的帮助很大
【解决方案2】:

你应该为每个线程创建这些对象之一(类名被省略,所以我不能具体说明),如果它不需要被共享。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多