JAVA多线程的安全问题

2020-06-25  本文已影响0人  代码阿强

线程是什么

要说线程首先必要了解一下什么是进程,进程的定义就是对代码块和数据的一次动态执行的过程。
比如说我们打开一个QQ,打开一个网页,这些都是进程,它都是在运行,那么为什么要提出线程呢?原因在于我们在进入一个网页的时候,它并不是一点击就立马能够打开,会存在一些延时,我们是可以在这个延时期间去做其他的事情。或者说我们可以再打开其他的网站嘛,不需要等当前我们这个正在打开的网站的加载。

通俗来说,线程就是程序把自己的任务让自己的线程去做,而且可以同时派生多个线程去处理不同的任务,我们可以理解成程序的程序。

画个图给大家理解一下


线程.jpg

给大家写一个银行存款的例子,帮助大家理解

//用户到银行存钱
public class User implements Runnable{
    
    private Bank bank;
    private int money;
    User(Bank bank)
    {
        this.bank=bank;
    }
    public void run() {
        for(int i=0;i<3;i++)
            bank.add(100);
            
    }
}
public class Bank {
    private int sum=0;
    
    void add(int money)
    {
        sum=sum+money;
        System.out.println("money----->"+sum);
    }
}

public class TestDemo {

    public static void main(String[] args) {
        Bank b=new Bank();
        User u1=new User(b);//用户1
        User u2=new User(b);//用户2
        Thread t1=new Thread(u1);
        Thread t2=new Thread(u1);
        t1.start();
        t2.start();
    }
}

打印一下

money----->100
money----->200
money----->300
money----->500
money----->400
money----->600

看起来没啥问题,我们再多打印几次

money----->200
money----->300
money----->200
money----->500
money----->600
money----->400

我们发现200出现了2次,100没有出现

安全问题

我们的要明白一个线程的执行有两个要点

执行资格:就是所需要除CPU以外的资源,这里是对象的创建
执行权限:分配CPU

一段程序的执行,必须要两者具备

    void add(int money)
    {
        sum=sum+money;
                //这里可能随时被其他线程插入
        System.out.println("money----->"+sum);
    }

单独把这段程序拎出来,第二次执行出现了两次200,就是因为线程0加了100之后,线程1又立马获得了CPU加了100,导致出现了两次200
安全问题就是线程最大的问题,所以我们需要找到一种解决这种问题的方法,也就是我们需要把对共享数据进行操作的语句保证只有一个线程参与,其他线程不参与执行即可

关键字:synchronized
锁的思想就是把代码块变成一个单独使用的一个区域,也就是说锁中的代码块,每次只能允许一个线程进行访问,需要详细了解锁,请访问Java锁机制那些事儿
这里只解释一下锁机制的使用原理和场景
利用锁机制对该代码块进行修改

public class User implements Runnable{
    
    private Bank bank;
    private int money;
    User(Bank bank)
    {
        this.bank=bank;
    }
    public void run() {
        for(int i=0;i<3;i++)
            bank.add(100);
            
    }
}
public class Bank {
    private int sum=0;
    Object obj=new Object();
    void add(int money)
    {
                synchronized(obj)//对象锁
                {
                  sum=sum+money;
                  System.out.println("money----->"+sum);
                  }
    }
}

public class TestDemo {

    public static void main(String[] args) {
        Bank b=new Bank();
        User u1=new User(b);//用户1
        User u2=new User(b);//用户2
        Thread t1=new Thread(u1);
        Thread t2=new Thread(u1);
        t1.start();
        t2.start();
    }
}
这样该代码就OK了,不会出现多个线程同时对sum进行操作,锁机制的本质就是防止多线程同时修改共享代码块

我再从生活中举一个锁机制的例子,帮助大家更加充分的了解锁的应用是如何防止多线程对共享数据进行操作的。

火车上的共享厕所

坐过火车的伙伴应该对火车上的厕所的使用不陌生,在厕所门口会有一个显式灯以及把手上面也会用红绿来代表里面是否有人。
现在我们可以把需要上厕所的人当作是一个线程,然后厕所作为一个共享数据,人想上厕所,需要抢夺厕所的使用权限,抢到的人就可以进去把门锁上,把手立马显示红色----里面有人,出来后显示绿色----里面无人,这个锁其实就是JAVA锁的来源。想要使用厕所就必须要争夺锁的使用权。
我个人就喜欢用一些比较生动的例子来理解各种原理,火车厕所的例子就可以非常好的理解整个JAVA的多线程的原理以及出现的问题和解决问题。

要解决安全问题,首先我们需要确认是否会出现安全问题,最合理的办法就是我们需要找出共享数据,然后设想多个线程如果同时对该共享代码块进行操作是否会出现数据混乱。

总结

多线程的安全问题的本质就是多个线程会可能同时对共享代码块进行操作,导致数据异常,合理的解决方案就是使用Java的锁机来确保同步代码块。只要出现了多线程,我们就需要判断是否会出现安全问题,关键在于我们需要找出共享数据

上一篇 下一篇

猜你喜欢

热点阅读