(46)多线程的安全问题解决方式:synchronized

来源:互联网 发布:动漫周边淘宝招聘 编辑:程序博客网 时间:2024/06/06 21:05

这里写图片描述

这种方式可能存在安全隐患。当0号线程执行到if(tick>0)时,为真,正好CPU切换线程到1,然后线程执行到if(tick>0)时,为真
…..可能所有的线程都卡在这了,然后再执行0号线程,tick=0,然后执行1号线程,tick=-1…….,出现错误数据

通过分析,发现,打印了0,-1,-2等错票
多线程的运行出现了安全问题

public class Demo implements Runnable{    private int tick=10;    Object obj=new Object();    public void run() {        while(true) {            if(tick>0) {                try {                    Thread.sleep(10);//对于sleep方法上声明抛出异常,就必须对此进行处理,但是不能在run上抛出,因为如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常 接口中的run没抛异常,所以实现中也不能抛出异常                } catch (Exception e) {                    // TODO Auto-generated catch block                }                System.out.println(Thread.currentThread().getName()+"sale:"+tick--);            }        }    }}

问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。

一、解决办法:
对多条操作共享数据语句,只能让一个线程都执行完,再执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了专业的解决方式:同步代码块
synchronized(对象){
需要同步代码块
}
对象如同锁,持有锁的线程可以在同步中执行。
没有持有锁的线程即使获得cpu的执行权,也进不去,因为没有获得锁
火车上的卫生间—经典

public class Demo implements Runnable{    private int tick=10;    Object obj=new Object();    public void run() {        while(true) {            *synchronized(obj)* {            if(tick>0) {                try {                    Thread.sleep(10);                } catch (Exception e) {                    // TODO Auto-generated catch block                }                System.out.println(Thread.currentThread().getName()+"sale:"+tick--);             }            }        }    }}

对synchronized解释:将synchronized理解成锁,默认这个锁是开启的1,当第一个线程要进入共享区时,先判断锁是开启的,进入共享区,并将锁置为0,然后执行代码,在try中睡眠(sleep)了,释放cpu,给其他的线程,注意此时共享区还是锁着的,其他共享数据线程进入后,判断锁为0,不能进入共享区,等到第一个线程醒了,执行完代码,然后将这个锁置为1,让其他线程访问。
二、同步的前提:

<font face="#FF0000">1.必须要有两个或者两个以上的线程2.必须是多个线程使用同一个锁必须保证同步中只能有一个线程在运行</font>

三、利弊
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源

阅读全文
0 0
原创粉丝点击