java - 在java中,使用synchronized方法能不靠谱吗?

标签 java methods concurrency synchronized

开门见山,我已经编写了一个代码来测试 java 中的并发性,使用同步方法:

代码:

public class ThreadTraining {

    public static class Value {

        private static int value;

        public static synchronized void Add() {
            value++;
        }

        public static synchronized void Sub() {
            value--;
        }

        public static synchronized int Get() {
            return value;
        }
    }

    public static class AddT implements Runnable {

        public static String name;

        public AddT(String n) {
            name = n;
        }

        @Override
        public void run() {
            while (Value.Get() < 100) {
                int prev = Value.Get();
                Value.Add();
                System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
            }
        }
    }

    public static class SubT implements Runnable {

        public static String name;

        public SubT(String n) {
            name = n;
        }

        @Override
        public void run() {
            while (Value.Get() > (-100)) {
                int prev = Value.Get();
                Value.Sub();
                System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
            }
        }
    }

    public static void main(String[] args) {
        Thread threads[] = new Thread[3];
        for (int i = 0; i < 4; i++) {
            if (i % 2 == 0) {
                threads[i] = new Thread(new AddT("Adder - Thread #" + i));
            } else {
                threads[i] = new Thread(new SubT("Subtractor - Thread #" + i));
            }
            threads[i].start();
        }
    }
}

尽管 “对同一对象的同步方法的两次调用不可能交错”,但这段代码很难执行。(来源:Oracle's concurrency tutorial - Synchronized methods),给出不可靠的输出,例如:(注意,输出中的任何非模式更改都在“...”行之间表示,不仅仅是不可靠的行为 )

-----[Thread #0 - Adder] has been created!
=====[Thread #0 - Adder] has been started!
-----[Thread #1 - Subtractor] has been created!
[Thread #0 - Adder] - changed value from 0 to 1
[Thread #0 - Adder] - changed value from 1 to 2
[Thread #0 - Adder] - changed value from 2 to 3
...\*goes on, adding as expected, for some lines*\
[Thread #0 - Adder] - changed value from 83 to 84
[Thread #0 - Adder] - changed value from 84 to 85
-----[Thread #2 - Adder] has been created!
=====[Thread #1 - Subtractor] has been started!
[Thread #0 - Adder] - changed value from 85 to 86
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 85 to 84
...\*goes on, subtracting as expected, for some lines*\
[Thread #1 - Subtractor] - changed value from -98 to -99
[Thread #1 - Subtractor] - changed value from -99 to -100 \*This thread ends here, as it reaches the state where (value>(-100))==false*\
=====[Thread #2 - Adder] has been started!
[Thread #2 - Adder] - changed value from -100 to -99
[Thread #2 - Adder] - changed value from -99 to -98
[Thread #2 - Adder] - changed value from -98 to -97
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from -67 to -66
[Thread #2 - Adder] - changed value from -66 to -65
-----[Thread #3 - Subtractor] has been created!
=====[Thread #3 - Subtractor] has been started!
[Thread #3 - Subtractor] - changed value from -65 to -66
[Thread #3 - Subtractor] - changed value from -66 to -67
...\*goes on as expected...*\
[Thread #3 - Subtractor] - changed value from -71 to -72
[Thread #3 - Subtractor] - changed value from -72 to -73 \*NOTE: From -73 it goes to -74, without a Subtractor-action in between! WTF???*\
[Thread #2 - Adder] - changed value from -74 to -73
[Thread #2 - Adder] - changed value from -73 to -72
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from 98 to 99
[Thread #2 - Adder] - changed value from 99 to 100 \*This adder ends here, adder thread #0 probably ends after next line...but not before doing something crazy!*\
[Thread #0 - Adder] - changed value from 85 to 86 \*What the hell are these values doing here? Oh wait, next lines is...*\
[Thread #3 - Subtractor] - changed value from -73 to -47\*...Holy mother of god!*\
[Thread #3 - Subtractor] - changed value from 100 to 99
[Thread #3 - Subtractor] - changed value from 99 to 98
...
[Thread #3 - Subtractor] - changed value from -98 to -99
[Thread #3 - Subtractor] - changed value from -99 to -100 \*The logical nightmare is finally over.*\

使用synchronized方法不靠谱吗?还是执行错误? (如果是,那是什么问题?如何解决?)

最佳答案

您的实现有点不对劲。 ‘Get’、‘Add’和‘Sub’都被锁定,但是你的‘Get’和你的加减法之间有一个间隙。刚刚执行“获取”的线程可以在那个间隙休息一下,其他人会更改该值。如果您希望多个方法调用都作为单个操作发生,则需要在比单个方法“更大”的事物上进行同步。

synchronized (Value.class) {
  int prev = Value.Get();
  Value.Add();
  System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}

请注意,这仍然存在一个问题,当您输入时 <100 可能仍然不正确,因此您应该重新检查它。 (当然,锁定 Class 对象并不是您通常希望在“真实”代码中执行的操作 :))

关于java - 在java中,使用synchronized方法能不靠谱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10606063/

相关文章:

python - 在 Python 中,如何在不将实例传递给它的情况下使用类方法?

java - ExecutorService 关闭钩子(Hook)

java - Firestore 添加具有引用属性的自定义对象

java - 使用带有反斜杠和 & 字符的正则表达式时,Mongo 找不到文档

java - 排序错误 : Hashmap<String, 列表 <String>>

java - 如何更改通用数组列表中的值?

swift - 如何在具有相似名称的 socket 上执行相同的方法,而不是写出数十次非常相似的行?

C++ 访问类内容器的 begin()/end() 方法

Java Fork 加入池卡住了

java - 关于Java生产者消费者解决方案的问题