线程干扰错误

来源:互联网 发布:进销存软件源码下载 编辑:程序博客网 时间:2024/06/05 00:53

两个线程读写同一个数据,将会导致的错误。

Counter由于这两个操作c都是单一的简单语句,因此可能看不到对交织实例进行操作。然而,即使简单的语句也可以转换为虚拟机的多个步骤。我们不会检查虚拟机所采取的具体步骤 - 只要知道单个表达式c++就可以分解成三个步骤:

检索当前值c。
将检索到的值增加1。
将增加的值存储回来c。
表达式c–可以以相同的方式分解,除了第二步减少而不是增量。

假设线程A increment在线程B调用的同一时间调用线程decrement。如果初始值c是0,他们的交错操作可能遵循如下顺序:

线程A:检索c。
线程B:检索c。
线程A:增加检索值; 结果是1。
线程B:减去检索值; 结果为-1。
线程A:将结果存储在c中; c现在是1。
线程B:存储结果c; c现在是-1。
线程A的结果丢失,被线程B覆盖。这种特定的交织只是一种可能性。在不同的情况下,线程B的结果可能会丢失,或者完全没有错误。因为它们是不可预知的,线程干扰的bug可能难以检测和修复。

import static org.junit.Assert.*;import org.junit.Test;/** *线程干扰,导致的错误的写  */public class TestInterference {    @Test    public void testIncremnet() throws InterruptedException{        Counter c = new Counter();        Thread add1 = new Thread(()->{for(int i=0;i<10000;i++) c.increment();});        Thread add2 = new Thread(()->{for(int i=0;i<10000;i++) c.increment();});        /**         * 测试两个线程同时增加10000次,而结果却少于20000         */        add1.start();        add2.start();        add1.join();        add2.join();        assertNotEquals(c.value(), 20000);    }    @Test    public void testInAndDe() throws InterruptedException{        Counter c = new Counter();        Thread add1 = new Thread(()->{for(int i=0;i<10000;i++) c.increment();});        Thread add2 = new Thread(()->{for(int i=0;i<10000;i++) c.decrement();});        /**         * 测试两个线程,一个增加10000次,另一个减少10000次,而结果却不为0         */        add1.start();        add2.start();        add1.join();        add2.join();        assertNotEquals(c.value(), 0);    }}class Counter {    private int c = 0;    public void increment() {        c++;    }    public void decrement() {        c--;    }    public int value() {        return c;    }}
原创粉丝点击