【问题标题】:Is lock.tryLock() thread Safe?lock.tryLock() 线程安全吗?
【发布时间】:2020-02-16 04:52:33
【问题描述】:

我尝试了使用同步、lock.lock() 和 lock.tryLock() 的线程竞赛程序,我发现使用同步和 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 实际输出:每次运行都是随机的

【问题讨论】:

    标签: java multithreading concurrency java-threads reentrantlock


    【解决方案1】:

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

    但是,您使用trylock 的方式会导致increment 和decrement 的非线程安全实现。如果你打算在这种情况下使用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) 适用于 Java 8 及更高版本,
    • java.util.concurrent.atomic.AtomicLong (javadoc) 自 Java 5 (含)以来的所有 Java 版本。

    显然LongAdder 在有很多争用的情况下表现更好:


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

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

    由此可见:

    • 如果算法在单处理器情况下不满足其行为规范,那么线程安全将毫无意义,并且
    • 如果算法不能使用多个处理器,线程安全就没有实际意义。

    【讨论】:

      猜你喜欢
      • 2020-04-15
      • 2011-07-04
      • 2014-04-26
      • 2012-11-30
      • 2010-12-30
      • 2013-03-12
      • 2021-08-03
      • 2010-12-27
      • 2018-06-04
      相关资源
      最近更新 更多