Java多线程-线程安全

Posted 长命百岁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:

 

以上是关于Java多线程-线程安全的主要内容,如果未能解决你的问题,请参考以下文章

多线程--线程安全

JAVA多线程_线程安全问题

Java面试题多线程-线程安全

怎样去写线程安全的代码(Java)

怎样去写线程安全的代码(Java)

java中多线程安全性和同步的常用方法