我有一个这样的代码块:
if(supportsSomeStuff()){
.....
.....
}
else {
.....
.....
}
现在我想把这段代码放在一个多读单写锁中。在这种情况下,是不是最好先在if语句中加锁,在if之后释放锁,然后在else语句中加锁,完成后再释放?
或者,我可以只为这种 if-else 情况设置一个锁,并在完成后释放它吗?
如果我需要对此做出决定,我需要考虑哪些因素?
如果您需要更多信息,请告诉我。
我有一个这样的代码块:
if(supportsSomeStuff()){
.....
.....
}
else {
.....
.....
}
现在我想把这段代码放在一个多读单写锁中。在这种情况下,是不是最好先在if语句中加锁,在if之后释放锁,然后在else语句中加锁,完成后再释放?
或者,我可以只为这种 if-else 情况设置一个锁,并在完成后释放它吗?
如果我需要对此做出决定,我需要考虑哪些因素?
如果您需要更多信息,请告诉我。
您是否正在考虑以下两种变体?
synchronized(lock) {
if(supportsSomeStuff()){
.....
}
else{
.....
}
}
对比
if(supportsSomeStuff()){
synchronized(lock) {
.....
}
}
else{
synchronized(lock) {
.....
}
}
它们之间唯一(巨大的)区别是if
语句内部的条件在后一种情况下不同步。此外(如果supportsSomeStuff()
可以在多个线程中执行)它们是等效的,尽管前一种情况持有锁的时间稍长。
您实际上并没有提供足够的信息来提供比一般答案更多的信息。
但总的来说,您应该尝试在以下各项之间找到最佳折衷方案:
这些竞争因素之间的最佳折衷究竟在哪里取决于您的情况。
顺便说一句,许多人建议内置“同步”锁,但由于您提到您只需要一个写入线程,那么根据您的情况,您可能会使用 ReentrantReadWriteLock 获得更好的吞吐量。
如果在此方法中您正在更改状态,则锁定该状态
假设您正在更改 StringBuilder 然后在您的 StringBuilder 上锁定名为 changedvalue 并且 supportsSomeStuff 是无状态的
if(supportsSomeStuff()){
//Considering that if will be executed when write needs to be done and else when read to be done
copyOnWriteStringBuilder = new StringBuilder(changingvalue.toString());//This will ensure that before every write you have taken a backup so concurrent read will see the last updated values
synchronized(changingvalue) {
//doSomething and then place the updated value in copyOnWriteStringBuilder too
}
}
else{
return copyOnWriteStringBuilder; // This piece for read no locking
}
我会说:
lock(); try { ... } finally { unlock(); }
模型来帮助您做出决定。如果代码更简洁,只需将整个 if 包装在该模型中,那么就可以使用它。我认为以下内容是最干净的,除非我遗漏了什么。
lock.lock();
try {
if(supportsSomeStuff()){
...
} else {
...
}
} finally {
lock.unlock();
}
如果您担心if
测试被锁定并且不需要被锁定,那么不要被锁定。您唯一应该担心的是测试本身是否调用了其他可能会影响您不需要并且不想被锁定的性能的方法。
读不是独占的,但写是独占的;这意味着可以有多个同时读取,但写入只能是一个,并且当写入发生时不允许读取。
这取决于你在哪里做什么。将您写入的块限制为最小。