lock.tryLock() 线程安全吗?



我尝试了使用Synchronization,lock.lock((和lock.tryLock((的线程竞赛程序,我发现使用sync和lock.lock((工作正常,但是lock.tryLock((本身不是线程安全的。此方法无法获取锁,因此会产生意外结果


import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {

Resources resources = new Resources();
Thread userThread1 = new Increment(resources);
Thread userThread2 = new Decrement(resources);
userThread1.start();
userThread2.start();
userThread1.join();
userThread2.join();
System.out.println(resources.getCounter());
}
}
private static abstract class UserThread extends Thread {
protected Resources resources;
public UserThread(Resources resources) {
this.resources = resources;
}
}
private static class Increment extends UserThread {
public Increment(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 10000; i++) {
resources.increemnt();
}
}
}
private static class Decrement extends UserThread {
public Decrement(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 10000; i++) {
resources.decrement();
}
}
}
private static class Resources {
public ReentrantLock getLock() {
return lock;
}
private ReentrantLock lock = new ReentrantLock();
public int getCounter() {
return counter;
}
private int counter = 0;
public void increemnt() {
if (lock.tryLock()) {
try {
counter++;
} finally {
lock.unlock();
}
}
}
public void decrement() {
if (lock.tryLock()) {
try {
counter--;
} finally {
lock.unlock();
}
}
}
}
}

预期: 0,0,0,0,0,0,0,0,0,0,0实际输出:每次运行时的随机输出

tryLock方法是线程安全的。 它可靠地完成它应该做的事情(根据javadoc

(。但是,使用trylock的方式会导致incrementdecrement的非线程安全实现。 如果您打算在这种情况下使用trylock,则需要执行以下操作:

try {
while (!lock.tryLock()) { }  // Try to get the lock until you get it
counter++;
} finally {
lock.unlock();
}

但这是一个坏主意,因为您实际上正忙于等待锁。 使用Lock更好的解决方案是:

try {
lock.lock();  // Block until the lock is acquired.
counter++;
} finally {
lock.unlock();
}

但是,如果您追求的是无锁解决方案,那么您应该使用原子类型:

  • java.util.concurrent.atomic.LongAdder(javadoc( for Java 8 及更高版本,
  • java.util.concurrent.atomic.AtomicLong(javadoc(自Java 5(包括Java 5(以来的所有Java版本。

显然,如果存在大量争用,LongAdder表现更好:

  • LongAdder 的性能如何优于 AtomicLong

请注意,线程安全实际上是一个难以精确定义的概念。 您需要从算法正确行为的行为规范开始。 然后你可以说是算法的实现。

定义:当算法在具有一个处理器的系统上运行时根据规范是正确的,那么当有多个处理器时,如果根据规范也始终正确,则该算法线程安全的

由此,我们看到:

  • 如果算法在单处理器情况下不符合其行为规范,则线程安全是没有意义的,并且
  • 如果算法不能使用多个处理器,则线程安全是没有意义的。

最新更新