【问题标题】:Java: Protecting an object from being accessed by multiple threadsJava:保护对象不被多个线程访问
【发布时间】:2015-07-10 20:56:45
【问题描述】:

我有一个 OpenGL ES 2.0 应用程序。在其中,我有一个类,它包含另一个类型的对象的数组,就像这样(这个问题被简化了):

public class StoreList(){

thisList StoreItems[];

    public StoreList(int nuberOfItems){

        thisList = StoreItems[numberOfItems];

    }

}

最初,我填充列表,然后在应用程序期间的某些时间点(当用户在“商店”场景中时),可以将新项目添加到列表中,例如,列表可以看起来像这样:

Before              After inserting object 'Fish' into index 1

Index 0  - Dog      Index 0 - Dog
Index 1  - Fox      Index 1 - Fish
Index 2  - Bird     Index 2 - Fox
Index 3  - Snake    Index 3 - Bird
                    Index 4 - Snake

现在,由于各种原因,此列表被迭代。例如,用于渲染、更新其位置等。

我遇到的问题是,我的应用程序使用 2 个线程 - GL 渲染线程和 Main/UI 线程。

当用户执行某个操作时,UI 线程调用一个“insertObject”方法,该方法插入一个额外的项目,如上所述。然而,渲染线程很乐意做这件事,如果它在调用“insertObject”的同时渲染索引 1 处的对象,那么它就会开始导致问题(列表中的每个对象都有不同数量的 openGL 四边形来绘制并且要绘制的数字包含在对象本身的变量中),因此如果索引 1 处的原始对象有 5 个四边形,而新对象只有 4 个,那么它开始尝试绘制第 5 个四边形,我们得到所有问题的方式(例如索引超出范围)。

render 方法、updateLogic 方法和 onTouchEvent 方法都声明为同步,但我仍然遇到问题。

我不确定如何确保 this 对象(StoreList 的实例及其中的所有内容以及它的“thisList”数组)一次只能从一个线程更新。

我看到的与并发问题有关的问题都是关于保护一个方法不被多个线程而不是对象调用,所以我有点困惑。

不胜感激。

【问题讨论】:

  • 也许CopyOnWriteArrayList 更适合您?
  • 最简单的方法:通过Lock 保护列表。每个要读取或写入列表的方法都需要先获取Lock。稍微复杂一点:尝试使用@synchronized。只要在@synchronized(如wait())中没有使用阻塞结构,这应该可以完成工作。
  • 感谢@Turing85,您的意思是在所有将读取/写入列表的代码上使用同步块吗? (使用列表本身作为锁定对象?)我只是想知道我是否可以简单地将读取/写入列表的任何方法声明为同步?我刚刚做到了,到目前为止没有崩溃(经过大约 30 次测试)。另外我不确定你的意思是'@synchronized'。你能举个例子吗?感谢您的帮助。
  • 我不知道 CopyOnWriteArrayList @RealSkeptic,很有趣!

标签: java concurrency thread-safety race-condition synchronized


【解决方案1】:

为什么不在 StoreItems 上使用同步块而不是同步插入/更新方法。同步块将保证任何时候只有一个线程可以执行插入代码块,或任何其他在同一对象(即 StoreItems)上同步的代码块(例如更新)。

【讨论】:

  • 标记为同步的方法不会锁定方法,如果它们是实例,它们会锁定对象的实例,如果它们是静态的,它们会锁定类。所以他们已经锁定了同一个对象。
  • 谢谢@RahulPrasad,有什么理由你更喜欢同步块而不是声明方法同步?
  • 正如 Mark 在上面的评论中指出的那样,通过同步方法,我们将获得对完整实例对象的锁定,这意味着没有其他线程可以在该实例对象上使用任何同步方法,而任何同步方法正在由一个线程运行。在您提供的代码 sn-p 和提出的问题中,重点放在了类成员“StoreItems”上;因此我建议在 StoreItems 上使用同步块并在其上获取锁,而不是在 StoreList 的实例上。此外,从安全角度来看,最好在私有 obj 上使用同步,而不是在方法上使用。
猜你喜欢
  • 2021-09-28
  • 2012-06-06
  • 1970-01-01
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多