您的位置:首页 > 其它

线程安全问题的详细解释与解决方法

2020-07-14 05:32 190 查看

首先,为什么会出现线程安全问题呢?
假设:新电影奥特曼大战灰太狼上映,这时候老板增设一台机器出售50张电影票, 一台机器出售电影票不会出现安全问题,但是由于电影太过奇葩,看得人持续增多,这时候一台机器已经不能满足购票需求。于是老板增设了一台机器,每台机器出售50张票。但是问题又来了,一台机器由于人很多,很快就出售完毕,另一台机器却出售一点点,于是老板想两台机器同时出售这100张电影票。这时候就可能出现线程安全问题
线程安全问题的几种表现:出现不存在的票,出现重复的票。
为什么会出现这种问题,那是因为几个线程共享了同一段资源,且同时对这一段资源进行修改或者其它操作。
代码演示:
这里对多线程的使用不熟悉的同学可以看多线程的使用连接

public class RunnableImpl implements Runnable{
//定义出售的票
private int ticket=100;
@Override
public void run(){
//这里使用while是为了让售票机出售电影票
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()
+”正在售卖第”+ticket+“张票”);
ticket--;
}
}

}
}

public class DemoTest{
public static void main(String[] args){
RunnableImpl r=new RunnableImpl();
Thread t0=new Thread(r);
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t0.start();
t1.start();
t2.start();
}
}

最后的结果会是这样子

为什么会出现重复的票呢?
当t0-t2都执行到System.out.println(Thread.currentThread().getName()
+”正在售卖第”+ticket+“张票”),ticket- -还没有执行的时候。
那么出现0,-1是怎么会是呢?
设t0执行到售卖最后一张票时,执行ticket- -;的时候,这时候恰好t1,t2执行到售出票的位置,这时候t1,t2还要继续执行,这时候就会出售不存在的票。
这个问题无疑是巨大的,要很好的解决这个问题,就要用到线程安全的知识。
解决:1.同步代码块synchronized
创建一个唯一锁对象
将同步的代码块锁住
例:我从上面的例子进行演示

public class RunnableImpl implements Runnable{
//定义出售的票
private int ticket=100;
//创建唯一锁对象
Object obj=new Object();
@Override
public void run(){
//这里使用while是为了让售票机出售电影票
while(true){
synchronized(obj){
if(ticket>0){
System.out.println(Thread.currentThread().getName()
+”正在售卖第”+ticket+“张票”);
ticket--;
}
}
}

}
}

synchronized实现原理
使用了对象监视器
线程在执行到这部分代码块的时候,会检查锁对象是不是存在,存在则进入执行,不存在则进行阻塞。
在同步代码块中的线程没有执行完,是不会释放锁对象。
2.同步方法
与同步代码块用法大致相同,只是将同步代码块用一个方法进行封装,唯一的区别就是不用创建锁对象(不用创建不代表没有,其中的锁对象是this),同时synchronized书写位置换到了方法void前。
与此还有静态同步方法,在常量中和方法中分别用static修饰,与上面不同的是,其锁对象是class的文件对象(反射)
3.lock锁(java.util.current.locks.Lock)
它具有与使用synchronized方法和语句所访问的的隐式监视器锁相同的基本行为和语句,但功能更强大
使用:创建ReentrantLock对象,在同步代码块前加入lock();进行锁住,结束后使用unlock释放锁

public class RunnableImpl implements Runnable{
//定义出售的票
private int ticket=100;
Lock l=new	ReentrantLock();
@Override
public void run(){
//这里使用while是为了让售票机出售电影票
while(true){
l.lock();
if(ticket>0){
System.out.println(Thread.currentThread().getName()
+”正在售卖第”+ticket+“张票”);
ticket--;
}
l.unlock();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐