我需要帮助理解以下代码:
private Predicate composedPredicate = null;
public boolean evaluate(Task taskData) {
boolean isReadLock = false;
try{
rwl.readLock().lock();
isReadLock = true;
if (composedPredicate == null) {
rwl.readLock().unlock();
isReadLock = false;
rwl.writeLock().lock();
if (composedPredicate == null) {
//write to the "composedPredicate" object
}
}
}finally {
if (isReadLock) {
rwl.readLock().unlock();
}else{
rwl.writeLock().unlock();
}
}
return composedPredicate.test(taskData);
}
如果我们在上面的代码中没有使用Read Locks,会发生什么? 喜欢:
public boolean evaluate(Task taskData) {
//boolean isReadLock = false;
try{
//rwl.readLock().lock();
//isReadLock = true;
if (composedPredicate == null) {
//rwl.readLock().unlock();
//isReadLock = false;
rwl.writeLock().lock();
if (composedPredicate == null) {
//write to the "composedPredicate" object
}
}
}finally {
rwl.writeLock().unlock();
}
return composedPredicate.test(taskData);
}
答案 0 :(得分:1)
您发布的第一个代码是使用读/写锁定在Java中使用双重检查锁定方法的正确实现。
没有读锁定的第二个实现被破坏了。内存模型允许写入从另一个线程的角度重新排序,看到写入内存的结果。
可能发生的是你可能在正在读取它的线程中使用了一个未完全初始化的Predicate实例。
代码示例:
我们的线程A和B都在运行evaluate
,而compositionPredicate最初都是null
。
composedPredicate
是null
Predicate
composedPredicate
composedPredicate
不 null
composedPredicate.test(taskData);
composedPredicate.test(taskData);
使用未完全初始化的实例运行,并且您的代码在生产中出现随机意外错误,从而导致贵公司遭受重大损失(可能会发生这种情况......取决于您正在构建的系统)步骤4和5的重新排序是否取决于许多因素。也许它只能在繁重的系统负载下运行。在您的操作系统,硬件,JVM版本等上可能根本不会发生这种情况(但是在下一版本的JVM,您的操作系统或将应用程序移动到其他物理机器时,它可能会突然开始发生)< / p>
糟糕的主意。
答案 1 :(得分:-1)
此代码类似于旧的&#39; Singleton模式&#39;使用同步块。 E.g。
class Singleton
{
Singleton s;
public static Singleton instance()
{
if(s == null)
{
synchronized(Singleton.class)
{
if(s == null)
s = new Singleton();
}
}
return s;
}
}
注意双重&#39;空检查&#39;只有第二个同步的地方。进行第一次“无效检查”的原因是&#39;是为了防止在调用instance()
方法时阻塞线程(因为当不为null时,它可以在没有同步的情况下继续)。
您的第一个代码也在做同样的事情。首先,它检查是否有分配给composedPredicate
的内容。如果不是这样的话,那么它只会获取一个writLock(它阻止所有其他Thread选择readLocks,它只会阻塞writeLocks)。
与单身模式&#39;的主要区别。而你的代码是你的价值可以重新确定。只有确保在修改过程中没有人读取值时,才能安全地进行此操作。通过删除readLock,您基本上可以创建一个线程在访问composedPredicate
时可能获得未定义结果(如果不是崩溃)而另一个线程正在修改该相同字段的可能性。
所以回答你的问题: 1.你不需要一个readLock来写,只需要一个writeLock(它会阻止所有其他试图锁定的线程)。但在这种设计模式中,你不能把它排除在外。 2.&amp; 3.见上面的解释。
希望这足以掌握这种模式。