简体   繁体   English

Java SynchronizedCounter无法按预期工作

[英]Java SynchronizedCounter does not work as expected

I have a class 我有一堂课

class SynchronizedCounter {
    private int i = 0;

    public synchronized void increment() {
        i++;
    }

    public synchronized void decrement() {
        i--;
    }

    public synchronized int getValue() {
        return i;
    }
}

which is used like that: 像这样使用:

public class CounterTest {
    public static void main(String[] args) throws InterruptedException {
        SynchronizedCounter c = new SynchronizedCounter();
        Thread d = new Thread(new D(c));
        Thread e = new Thread(new E(c));
        d.start();
        e.start();
        System.out.println(c.getValue());           
    }
}

where class D is implemented as follows: D类的实现方式如下:

class D implements Runnable {
    private SynchronizedCounter counter;

    D(SynchronizedCounter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        counter.increment();
    }
}

Class E has only one different line in comparison to the class D 与D类相比,E类只有一条不同的线

 counter.decrement();

in it's run method. 在它的运行方法中。

I would expect to have always 0 printed because the methods of the SynchronisedCounter class are all synchronised, however I get 1 sometimes. 我希望总是打印0,因为SynchronizedCounter类的方法都已同步,但是有时我得到1。 Could you explain me please what is wrong with this code? 您能否解释一下这段代码有什么问题? When I run d.start() and e.start() in synchronized(c) block then it works as expected, the same happens when I add d.join() after d.start() and e.join() after e.start(). 当我在synced(c)块中运行d.start()和e.start()时,它可以按预期工作,当我在d.start()之后添加d.join()并在之后添加e.join()时,也会发生同样的情况e.start()。

You're making a lot of assumptions about threads which do not hold true. 您对线程不正确的假设很多。 The two main assumptions of yours which do not hold true are these: 您的两个不成立的主要假设是:

  • All threads run at the same speed. 所有线程以相同的速度运行。
  • All threads are started immediately. 所有线程立即启动。

The execution sequence is random. 执行顺序是随机的。 The threads run concurrently. 线程同时运行。 In the following, sequence means the sequence in which the threads hit SynchronizedCounter via the method calls. 在下文中,序列是指线程通过方法调用命中SynchronizedCounter的序列。 Because that's what synchronized does, it forces concurrent threads into sequential access by guarding it with a monitor (if you don't know what a monitor is, read mutex semaphore instead, it's different, but for this explanation the difference isn't important). 因为这就是synchronized功能,所以它通过使用监视器来保护并发线程以使其顺序访问(如果您不知道监视器是什么,则改为读取互斥量信号灯,这是不同的,但是对于此说明,差异并不重要) 。 You can expect any of the following three outputs: 您可以期望以下三个输出中的任何一个:

  • 0 in case the sequence was D, E, main; 如果序列为D,E,main,则为0 ;否则为0 or E, D, main; 或E,D,主要; or main, D, E; 或主D,E; or main, E, D. 或主要的E,D。
  • 1 in case the sequence was D, main, E 1的情况下,该序列是d,主,E
  • -1 in case the sequence was E, main, D. 如果序列是E,main,D,则为-1

Threads are not started immediately 线程不会立即启动

When you invoke new Thread().start() , the Thread becomes runnable. 当您调用new Thread().start() ,该Thread将变为可运行状态。 But it is up to the scheduler to decide when the thread actually gets CPU time. 但是,由调度程序决定线程何时实际获得CPU时间。 And that depends on factors outside the realm of a program's influence, sometimes even outside the realm of a VM's influence. 而且这取决于程序影响范围之外的因素,有时甚至取决于VM影响范围之外的因素。 For example, how close any of the existing threads is to being preempted because of exhausting its timeslice, or whether idle CPU cores are available right now. 例如,由于耗尽其时间片,任何现有线程有多接近要被抢占,或者当前空闲的CPU内核是否可用。

Threads run at different speeds 线程以不同的速度运行

The speed of a thread is determined by various factors which are outside the realm of a program's influence. 线程的速度取决于程序影响范围之外的各种因素。 For example, if the thread wants to access data, whether that data is cached or not, and in which cache it is, to give just one example. 例如,如果线程想要访问数据,则仅举一个示例,无论该数据是否被缓存以及缓存在哪个缓存中。

The output -1 is the most unlikely output, but even that output cannot be ruled out completely. 输出-1是最不可能的输出,但是甚至不能完全排除该输出。 And that "unlikely" is also purely based on assumptions made from observations of how virtual machines usually behave, and it is not anything that can be relied upon. 而且,“不太可能”也完全基于对虚拟机通常如何运行的观察得出的假设,而这并不是可以依靠的任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM