线程安全问题的详细解释与解决方法
首先,为什么会出现线程安全问题呢?
假设:新电影奥特曼大战灰太狼上映,这时候老板增设一台机器出售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(); } } }
- 可写静态数据(WSD):问题解释和解决方法(转) --- TLS
- UNIX网络编程卷1(第三版)关于源程序编译出错问题的详细解决方法
- 2009-05-13 21:11 IIS 安装包详细安装方法..及各类问题解决
- 在不重启的情况下新增一块磁盘中出现的问题以及挂载到对应的目录下的详细解决方法
- 编写SqlHelper使用,在将ExecuteReader方法封装进而读取数据库中的数据时会产生Additional information: 阅读器关闭时尝试调用 Read 无效问题,解决方法与解释
- ie7下z-index失效问题解决方法(详细分析)
- 主从遇到的各种问题的详细解决方法
- Tensorflow训练完模型model使用 Redis并发加载 造成内存泄露问题,详细讲解如何查找问题以及解决方法
- php -- 解决php连接sqlserver2005中文乱码问题(附详细解决方法)
- 编写SqlHelper使用,在将ExecuteReader方法封装进而读取数据库中的数据时会产生Additional information: 阅读器关闭时尝试调用 Read 无效问题,解决方法与解释
- 23 API-多线程(多线程概述,多线程实现方案,线程控制常见方法,线程安全问题及解决)
- java语言基础(91)——多线程(同步方法解决线程安全问题)
- C++解决约瑟夫问题,猴子称王,丢手绢问题(详细解释)
- 多线程-同步代码块解决线程安全问题的解释以及同步的特点及好处和弊端
- Json日期格式问题的四种解决方法(超详细)
- 比较详细的win2003 IIS6.0 301重定向带参数的问题解决方法
- ie7下z-index失效问题解决方法(详细分析)
- 安装MySQL数据库最后一步出现无法响应问题详细解决方法
- 总结用cygwin+eclipse+NDK编译hellojni的详细步骤,以及所遇到问题的解决方法
- ie7下z-index失效问题解决方法(详细分析)