Java中的简单同步

时间:2018-05-16 13:59:34

标签: java multithreading synchronization

我正在研究有关同步的Oracle文档,并且有这个类计数器:

-- Create tables
CREATE TABLE initialValues(
  id serial PRIMARY KEY,
  value int
);

CREATE TABLE addOne(
   id serial,
   id_init_val int REFERENCES initialValues(id),
   value int
);

-- Init values
INSERT INTO initialValues(value)
SELECT a.n
FROM generate_series(1, 100) as a(n);

-- Insert values in the second table by selecting the ones from the 
-- First one .
WITH init_val as (SELECT i.id,i.value FROM initialValues i)
INSERT INTO addOne(id_init_val,value)
(SELECT id,value+1 FROM init_val);

他们用两个线程解释了一些可能的错误交错,我试着写一个程序来测试这些糟糕的交错:

class Counter {
    int c = 0;

    public void increment() {
        c++;
    }

    public void decrement() {
        c--;
    }

    public int value() {
        return c;
    }
}

但无论对c的访问是否同步,我总是得到0,0和0的值,我不知道为什么。

有人可以帮助我吗? 最好的问候。

3 个答案:

答案 0 :(得分:2)

巧合,这是我机器上的结果:

1
0
0

Process finished with exit code 0

而且,如果你再试一次,

for (int i = 0; i < 100; i++) {
    Counter counter = new Counter();
    AdderCounter ac = new AdderCounter(counter);
    SubberCounter sc = new SubberCounter(counter);
    Thread t1 = new Thread(ac);
    Thread t2 = new Thread(sc);

    t1.start();
    t2.start();

    t1.join();
    t2.join();
    System.out.println(counter.c);
    System.out.println();
}

你可能会得到这个:

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

-1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

1
0
0

答案 1 :(得分:2)

您需要并行运行add / sub 多次次。

private static final int COUNT = 1000000;

class Counter {
    int c = 0;

    public void increment() {
        c++;
    }

    public void decrement() {
        c--;
    }

    public int value() {
        return c;
    }
}

class AdderCounter implements Runnable {
    Counter counter;

    public AdderCounter(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        for (int i = 0; i < COUNT; i++) {
            counter.increment();
        }
    }
}

class SubberCounter implements Runnable {
    Counter counter;

    public SubberCounter(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        for (int i = 0; i < COUNT; i++) {
            counter.decrement();
        }
    }
}

public void test() throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        Counter counter = new Counter();
        AdderCounter ac = new AdderCounter(counter);
        SubberCounter sc = new SubberCounter(counter);

        Thread t1 = new Thread(ac);
        Thread t2 = new Thread(sc);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(counter.c);
    }
}

这一次打印:

  

-33852

     

28937

     

-546

     

-678544

     

-653775

     

358351

     

-593183

     

1000000&lt; - 现在这是一个真正的巧合:)

     

-826735

     

-773183

对我来说,如果没有发生线程争用,你会期望0

BTW:不要在测试中添加println语句 - 在测试时使用IO会使交错更不可能,因为大多数时候代码都在进行I / O操作

答案 2 :(得分:1)

对于并发程序中的错误,可能最糟糕的事情是它们通常不会出现。您可以在本地计算机上运行该程序数千次,它运行正常。然后你将它移动到一个服务器,这个服务器被数以百万计的人访问,并且事情开始“无缘无故”地破坏。