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(智能感知AJAX,从后台调数据)
    jQuery插件(输入关键字出现提示,并可查询)
    设置缓存失效的三种方法
    关于fluorinefx基础和服务器搭建的文章地址
    关于过河问题的感悟
    .net 大文件上传
    iis7中运行cmd
    学习总结
    C#开源资源项目(转载)
    HTML数据提取
  • 原文地址:https://www.cnblogs.com/oscar1987121/p/10220639.html
Copyright © 2011-2022 走看看