在java中,可以使用synchronized方法不可靠吗? [英] In java, can the use of synchronized methods be unreliable?

查看:140
本文介绍了在java中,可以使用synchronized方法不可靠吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

直接到这一点,我已经做了一个代码来测试java中的并发,使用同步方法:

Going straight to the point, i have made a code to test concurrency in java, using synchronized methods:

代码:

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并发教程 - 同步方法),给出不可靠的输出,如下所示:(注意<输出中的模式变化在<...>行之间表示不仅仅是不可靠的行为

This code, tough, has an unreliable execution despite the fact "it is not possible for two invocations of synchronized methods on the same object to interleave." (Source: Oracle's concurrency tutorial - Synchronized methods), giving outputs that are unreliable, such as the following: (note, any non-patternful changes in the output are denoted between the "..." lines, not just unreliable behavior)

-----[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.*\

是否使用同步方法不可靠?还是是实现错了? (如果是这样,那么是什么错了呢?如何解决?)

Is the use of synchronized methods unreliable? Or is the implementation wrong? (If so, what is wrong then? and how to fix it?)

推荐答案

'Get','Add'和'Sub'都被锁定,但是'Get'和你的加法或减法之间有一个差距。刚刚Get的线程可以在那个间隙期间休息,有人改变了值。如果您希望多个方法调用都作为单个操作发生,您需要在比单个方法更大的某个方法上同步。

Your implementation is a bit off. 'Get', 'Add' and 'Sub' are each locked, but there is a gap between your 'Get' and your addition or subtraction. The thread that just did 'Get' can take a break during that gap, and someone else changes the value. If you want multiple method calls to all happen as a single operation, you need to synchronize on something "larger" than the individual method.

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

注意,这仍然有一个问题,< 100可能不是真的你输入,所以你应该重新检查它。 (当然锁定一个Class对象不是你通常想要在真正的代码:))

Note this still has a problem where <100 might not still be true when you enter, so you should recheck it. (and of course locking on an Class object isn't something you'd generally want to do in 'real' code :) )

这篇关于在java中,可以使用synchronized方法不可靠吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆