zoukankan      html  css  js  c++  java
  • Java多线程-线程安全

    1. 数据不共享的情况

    在探讨数据共享的话题前,先来看看数据不共享的情况,每一个线程里面的数据都是独立的,就像下面的例子,3个线程,每一个线程自己对自己的数据进行扣减,直到0为止

    public class TestThread {
        public static void main(String[] args) {
    
            MyThread myThread_A = new MyThread("A");
            MyThread myThread_B = new MyThread("B");
            MyThread myThread_C = new MyThread("C");
    
            myThread_A.start();
            myThread_B.start();
            myThread_C.start();
    
        }
    
    }
    
    class MyThread extends Thread {
    
        private int count = 5;
        private String name;
    
        public MyThread(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            // super.run();
    
            while (count != 0) {
                System.out.println(name + " = " + count);
                count--;
            }
        }
    }

    运行结果:

    2. 数据共享的情况

    这里有一段测试代码,看看共享数据的结构,按照理想的情况下,MyRunnable只实例了一次,所以里面的count=5将会被扣减5次,打印的结果应该是,5,4,3,2,1,因为这里有5个线程,每次调用run的时候,都会减去1,但是结果,确实有点出乎意外....而且每一次执行的结果都不一样

    public class TestThread {
        public static void main(String[] args) {
    
            //新建一个带有Runnable接口的类
            MyRunnable myRunnable = new MyRunnable();
    
            //新建5个线程,但使用了同一个Runnable实例对象,意味着里面的数据是共享的
            //这里的Thread(Runnable,String)是一个构造函数,第一次参数为Runnable接口,第二个为线程名称
            Thread thread_A = new Thread(myRunnable,"A");
            Thread thread_B = new Thread(myRunnable,"B");
            Thread thread_C = new Thread(myRunnable,"C");
            Thread thread_D = new Thread(myRunnable,"D");
            Thread thread_E = new Thread(myRunnable,"E");
    
            thread_A.start();
            thread_B.start();
            thread_C.start();
            thread_D.start();
            thread_E.start();
    
        }
    
    }
    
    class MyRunnable implements Runnable {
    
        private int count = 5;
    
        public MyRunnable() {
        }
    
        @Override
        public void run() {
            // super.run();
            System.out.println("当前线程名称" + Thread.currentThread().getName() + " = " + count);
            count--;
    
        }
    }

    运行结果1:

    运行结果2:

     

    运行结果3:

     

    3.线程不安全

    经过上面的例子隐身出了一个问题,就是线程安全问题,在实际场景当中,这是一个非常危险的问题,例如在双11,秒杀,活动中,很多买家同时在0点的时候按购买,但货品只有1个,很明显这里就是多线程处理同一个数据(货品库存量),那如果在线程不安全的情况下,会出现更上面例子一样的情况,两个人同一时间都在对同一个数字进行处理,结果有可能是,多名买家同时获得这个商品。

    为什么这样呢,主要原因是count--这个代码,一般情况,这行代码做了3个动作

    1. 获取count当前的值
    2. 对count的值进行-1的动作
    3. 对count重新赋值

    那问题很明显就出在第一步,假如A线程运行到这一行代码获取到count的值为5,接下来,B线程抢到CPU的使用前,他也执行到了这行代码,获取count的值也是5,因为A线程还没有进行-1的操作

    4.线程安全

    那怎么办呢,关键字synchronized,在run方法前加上这句的代码就可以达到排队执行方法的作用了,意思就是说,在执行run代码的时候,线程先查看当前代码块有没有钥匙,如果有钥匙,即可进入这扇门(代码块),然后执行里面的内容,执行完之后就会把钥匙交出来,由下一个抢到钥匙的人进入,并执行里面的内容。在这个抢钥匙的过程中是人人平等,谁先抢到钥匙,谁先进入。我们叫这块区域“互斥区”。

    class MyRunnable implements Runnable {
    
        private int count = 5;
    
        public MyRunnable() {
        }
    
        @Override
        synchronized public void run() {
            // super.run();
            System.out.println("当前线程名称" + Thread.currentThread().getName() + " = " + count);
            count--;
    
        }
    }

    运行结果1:

    运行结果2:

  • 相关阅读:
    jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
    jQuery 源码解析(二十三) DOM操作模块 替换元素 详解
    jQuery 源码解析(二十二) DOM操作模块 复制元素 详解
    jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
    jQuery 源码分析(二十) DOM操作模块 插入元素 详解
    jQuery 源码分析(十九) DOM遍历模块详解
    python 简单工厂模式
    python 爬虫-协程 采集博客园
    vue 自定义image组件
    微信小程序 image组件坑
  • 原文地址:https://www.cnblogs.com/oscar1987121/p/10220639.html
Copyright © 2011-2022 走看看