好记性不如烂笔头75-多线程-并行访问下的资源竞争和样例

来源:互联网 发布:算法第四版英文版pdf 编辑:程序博客网 时间:2024/05/29 14:07

在实际业务常见中,很多的时候我们都需要访问一些共同的资源,比如一个序列号,比如某一个文件。如果多个线程一起访问这个序列或者文件,而我们没有做足够多的处理,就很容易造成脏数据或者数据丢失等各种问题。
这种场景特别常见,写一个简单的例子。以免自己的团队在实际开发中,犯这种小错误。
当然,这种错误知道了,要预先处理还是相当简单;但是如果要真的出现了错误,在一大堆代码中找这个坑,那是相当的要命。

样例的场景

我们的业务需要获取一个序列号。下面是一个取得序列号的单例模式的例子,但调用get()时,可能会产生两个相同的序列号:
当代码(1)和(2)都试图调用get()取得一个唯一的序列。当代码(1)执行完代码(a),正要执行代码(b)时,它被中断了并开始执行代码(2)。一旦当代码(2)执行完(a)而代码(1)还未执行代码(b),那么代码(1)和代码(2)就将得到相同的值。

简单多线程并行访问下的资源竞争的java源代码

package com.thread;/** * 简单用多线程获取序列号,理论上能出现序列号重复,但是要观察到,可能需要多次试验和仔细观察 * 小技巧:我们这里有30次循环,如果打印出的结果中,没有30,那么就可能出现了重复 * @author 范芳铭 */public class EasyGetSeq extends Thread {    private static int number = 0;    private static EasyGetSeq seq = new EasyGetSeq();    public EasyGetSeq(String name){        super(name);    }    private EasyGetSeq() {    }    public   EasyGetSeq getInstance() {        return seq;    }    public  int get() {        number++; // (a)        return number;// (b)    }    public void run(){        for (int i = 0 ; i < 10; i ++){            int a = getInstance().get();// (1)            System.out.println(Thread.currentThread().getName() + ":" + a);            //模拟访问停顿            try {                Thread.sleep(10);            } catch (Exception e) {                e.printStackTrace();            }        }       }    public static void main(String[] args) {        //简单模拟多线程调用        EasyGetSeq sepA = new EasyGetSeq("A");        sepA.start();        EasyGetSeq sepB = new EasyGetSeq("---B");        sepB.start();        EasyGetSeq sepC = new EasyGetSeq("======C");        sepC.start();    }}

运行结果
A:1
======C:3
—B:2
—B:5
======C:4
A:4
======C:7
—B:6
A:6
—B:9
A:8
======C:10
======C:12
—B:13
A:11
======C:14
A:16
—B:15
—B:18
======C:19
A:17
======C:20
—B:22
A:21
—B:23
======C:25
A:24
—B:26
A:27
======C:26

观察的小技巧,因为我们运行的次数是 3*10,因此最终的数据应该是30,但是这里没有出现30和29,那么肯定有一些数字发生了重复,比如
—B:26
A:27
======C:26

0 0
原创粉丝点击