多线程安全问题
2016-05-07 11:19
204 查看
在上一个卖票实例(买票案例)中,我们在Ticket类中定义了run()方法:
为了清楚的展示该实例存在安全问题,我们在其中加入能让线程进行切换的代码:
注意:sleep(long millis)方法声明了一个异常InterruptedException(中断异常),所以我们在run()方法中用到这个方法时应在run()里声明或抛出,但是run()方法是覆盖的Runnnable接口中的run()方法,而接口是没有没有声明过异常的,所以覆盖时也不能声明异常,此时只能try-catch。
运行如下代码:
可以看到,结果中出现了0号、-1号、-2号票,而现实中根本不能存在这样的票号,这就出现了线程中的安全问题。
线程安全问题产生的原因:
1.多个线程在操作共享的数据
2.操作共享数据的线程代码有多条
所以,当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
为了避免线程安全问题的产生,我们要解决可能发生的隐患,解决思想如下:
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块来解决这个问题,同步代码块的格式:
运行结果(部分):
可以发现同步解决了线程的安全问题。
引申:
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。
public void run() { while(true) { if(num>0){ System.out.println(Thread.currentThread().getName()+"卖"+num--+"号票"); } } }
为了清楚的展示该实例存在安全问题,我们在其中加入能让线程进行切换的代码:
public void run() { while(true) { if(num>0){ //sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) Thread.sleep(10); System.out.println(Thread.currentThread().getName()+"卖"+num--+"号票"); } } }
注意:sleep(long millis)方法声明了一个异常InterruptedException(中断异常),所以我们在run()方法中用到这个方法时应在run()里声明或抛出,但是run()方法是覆盖的Runnnable接口中的run()方法,而接口是没有没有声明过异常的,所以覆盖时也不能声明异常,此时只能try-catch。
public void run() { while(true) { if(num>0){ try { Thread.sleep(10); } catch(InterruptedException e) { //此时先不做处理 } System.out.println(Thread.currentThread().getName()+"卖"+num--+"号票"); } } }
运行如下代码:
class Ticket implements Runnable{ private int num=100; //共有100张票 public void run() { while(true) { if(num>0){ try{Thread.sleep(10); } catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"卖"+num--+"号票"); } } } } public class Demo { public static void main(String[] args) { Ticket t=new Ticket(); //创建一个线程任务对象 //创建线程 Thread t1=new Thread(t); //任务对线程进行初始化 Thread t2=new Thread(t); Thread t3=new Thread(t); Thread t4=new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }运行结果(部分):
可以看到,结果中出现了0号、-1号、-2号票,而现实中根本不能存在这样的票号,这就出现了线程中的安全问题。
线程安全问题产生的原因:
1.多个线程在操作共享的数据
2.操作共享数据的线程代码有多条
所以,当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
为了避免线程安全问题的产生,我们要解决可能发生的隐患,解决思想如下:
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块来解决这个问题,同步代码块的格式:
synchronized(对象) //这里的对象可以随便创建,一般我们可以创建Object类的对象 { //需要被同步的代码 }将同步代码块添加到run()方法中,运行如下代码:
class Ticket implements Runnable{ private int num=100; //共有100张票 Object obj=new Object(); public void run() { while(true) { synchronized(obj) //同步 { if(num>0){ try{Thread.sleep(10); } catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"卖"+num--+"号票"); } } } } } public class Demo { public static void main(String[] args) { Ticket t=new Ticket(); //创建一个线程任务对象 //创建线程 Thread t1=new Thread(t); //任务对线程进行初始化 Thread t2=new Thread(t); Thread t3=new Thread(t); Thread t4=new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果(部分):
可以发现同步解决了线程的安全问题。
引申:
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。
相关文章推荐
- 为iPhone6设计自适应布局(二)
- tp框架那里
- JS计算字符串的长度
- 二叉树的线索化
- 人活着系列之芳姐和芳姐的猪(sdut_2929)
- 设计模式之策略模式(包含与简单工厂模式的区别,实现了超市结账系统)
- hdu2084 数塔 (DP)
- uri中为什么本地文件file后面跟三个斜杠, http等协议跟两个斜杠?
- java I/O (二)——对象序列化
- Unity3D 场景平移、缩放
- 面向项目(五)—— #pragma
- 实习面经--腾讯 后台开发 v1
- Mysql中约束详解
- TCP对SACK的处理以及乱序的处理细节
- 设计模式之策略模式(包含与简单工厂模式的区别,实现了超市结账系统)
- IOS各种集合遍历效率对比
- RelativeLayout属性大全
- android 抓包 使用 tcpdmp + Wireshark
- 给你5个数a,b,c,d,k。x属于[a,b]y属于[c,d]。 问你有多少对(x,y)的公约数为k
- java 怎么判断文本内容的编码格式