zoukankan      html  css  js  c++  java
  • 多线程编程之竟态

    一.竟态

      1.竟态的概念

           竟态指计算结果的正确性依赖相对时间顺序和线程的交错,通俗的说就是计算结果与时间有关,对于一个同样的输入,有时候结果正确,有时候结果不正确。

           竟态不一定会导致结果错误,只是说有这种导致结果出错的可能性。

        2.模拟竟态的产生

        下面有一个模拟请求Id生成器,让多个线程随机生成请求id.

    public final class RequestIdGenerator {
    
        private final static RequestIdGenerator INSTANCE = new RequestIdGenerator();
        private final static short SEQ_UPPER_LIMIT = 999;
        private short sequence = -1;
        
        private RequestIdGenerator() {
            
        }
        
        public static RequestIdGenerator getInstance (){
            return INSTANCE;
        }
        
        public short nextSequence() {
            if (sequence >= SEQ_UPPER_LIMIT) {
                sequence = 0;
            } else {
                sequence++;
            }
            return sequence;
        }
        
        public String nextId() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
            String timeStamp = sdf.format(new Date());
            DecimalFormat df =new DecimalFormat("000");
            short sequenceNo = nextSequence();
            return "0049"+timeStamp+df.format(sequenceNo);
        }
    }
    View Code

        测试类:

    public class RaceConditionDemo {
        
        public static void main(String[] args) {
            int numberOfThreads = Runtime.getRuntime().availableProcessors();
            Thread[] workThreads = new Thread[numberOfThreads];
            System.out.println(numberOfThreads);
            for (int i = 0; i< numberOfThreads; i++) {
                workThreads[i] = new WorkerThread(i, 10);  
            }
            for (Thread t : workThreads) {
                t.start();
            }
        }
          static class WorkerThread extends Thread {
                private final int requestCount;
                public WorkerThread (int id, int requsetCount) {
                    super("worker-"+id);
                    this.requestCount = requsetCount;
                }
                @Override
                public void run() {
                    int i =requestCount;        
                    RequestIdGenerator generator = RequestIdGenerator.getInstance();
                    while (i-- > -1) {
                        String requestID = generator.nextId();
                        processRequest(requestID);
                    }    
                }
                private void processRequest(String requestID) {
                    Tools.randomPause(50);
                    System.out.println(Thread.currentThread().getName()+" "+requestID);
                }
                
          }
    }
    View Code

        

        按理说每个线程不同时间生成的请求id应该都是不同的,但是多次执行会发现有时候请求id是相同的。

        这也就是说执行结果正确与否与时间相关,即出现了竟态。

      3.竟态结果分析

         分析可见nextSequence()这个方法导致了不同的线程拿到了相同的requestId,因为RequestIdGenerator这个类中有一个共享的全局变量sequence,多个线程并发的读取更新

    sequence导致了竟态的出现。即一个线程对sequence所做的更新可能被其它线程的更新而覆盖掉,导致数据出现脏读。

           4.竟态的两种模式

        ①read-modify-write(读-改-写)

          即读取一个共享变量的值(read),然后根据值做一些计算(modify),最后更新该变量的值(write).

         例如sequence++就是如此,过程指令如下:

          1.从内存中将squence的值读取到寄存器r1中

          2.r1的值加1

          3.将r1的值更新到sequence变量的内存空间中

             在多线程环境下,某个线程执行完1后,可能其他线程已经更新了sequence的值,但是该线程却仍然使用r1未更新的值去操作2,3指令,造成丢失更新和脏读。

        ②check-then-act(检测而后行动)

                  以下面这段代码为例:

    public short nextSequence() {
            if (sequence >= SEQ_UPPER_LIMIT) {    //步骤1
                sequence = 0;          //步骤2.1
            } else { 
                sequence++;                  //步骤2.2
            }
            return sequence;
        }

          检测而后行动指读取某个共享变量的值,根据该值做一些判断,然后根据该判断结果去条件执行一些操作。

          在多线程环境下,可能当某个线程执行完步骤1后,其它线程更新了sequence的值,此时该线程仍然根据之前的判断去做一些操作,也会造成丢失数据更新和脏读。

        

         

        

  • 相关阅读:
    【Leetcode】113Path Sum II
    【leetcode】112. Path Sum
    virtualbox 中安装win7虚拟机
    制作一个vagrant的win7 box
    socket编程
    异常处理
    strip(),replace()和re.sub()用法
    面象对象 高阶篇
    面象对象 基础篇
    Subprocess模块介绍
  • 原文地址:https://www.cnblogs.com/goxcheer/p/9351800.html
Copyright © 2011-2022 走看看