多线程__【线程安全】【线程同步】【单例模式的线程安全】【线程死锁】
2013-12-06 16:37
246 查看
线程安全问题
线程安全问题产生的原因:多条线程代码操作共享数据,一条线程还未执行完,并对结果进行反馈;其他的线程通过条件判断参与进运算,对数据重复操作多次启动一个线程是非法的,尤其是线程已经结束后,不能重新启动
买票示例
/*卖票示例 */ class Ticket implements Runnable { private int num = 100; public void sale() { while (true)// { if (num>0) { try//使用sleep方法时会出现异常,继承的接口没有继承Exception 异常,所以run方法不能throws,只能try catch { Thread.sleep(10);//线程休眠10毫秒 } catch (InterruptedException e) { } System.out.println("name: "+Thread.currentThread().getName()+"....."+num--); } } } public void run() { sale(); } } class TicketDemo { 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(); } }
运行结果出现负数票
解决方法:
当前线程执行完毕后,其它线程才能参与运算。
将共享数据的代码封装起来,当有线程在执行这些代码的时候。其它线程不可以参与运算,使用
线程同步
class Ticket implements Runnable { private int num = 100; Object obj =new Object(); public synchronized void sale()//同步函数,不能直接调用,因为一个线程进入后全部执行完才出来,其它线程没有锁所以执行不到 { while (true) { // synchronized(obj)//同步代码块,同步锁;需要传入对象,可以是任意对象,作为自定义锁 // { if (num>0) { try { Thread.sleep(10);//线程休眠10毫秒 } catch (InterruptedException e) { } System.out.println("name: "+Thread.currentThread().getName()+"....."+num--); } // } } } public void run()//所有线程都可以调用run方法,在run方法中间接调用同步函数,从而间接执行到sale(); { sale(); } }
对象如同锁,同步就相当于一个保险箱,持有锁的线程可以进入同步中执行,没有锁的线程即使获取cpu执行权,也无法进去执行
经典实例----火车上的卫生间
同步的前提:多个线程使用同一个锁,必须保证同步中只有一个线程在执行
同步的弊端:多个线程需要判断锁,较为消耗资源
同步的原则:明确哪些代码是多线程运行代码;明确共享数据;明确多线程运行代码哪些是操作共享数据的,只能有一个共同的锁
同步的方式
①同步代码块synchronized(对象){需要被同步的代码}//只需要把需要同步的代码封装在同步中,同步代码块的锁是传入的对象,可以是任意对象,自定义锁。
②同步函数
同步函数的锁:函数需要被对象调用,那么函数都有一个所属对象的引用,就是this。即当前任务对象
(考点)静态同步函数使用的锁是该方法所在类的字节码文件对象,类名.class
静态成员进内存的过程:内存中没有本类对象,但是一定有该类对应的字节码文件对象,类名.class,该对象的类型是class
总结:同步函数中,那个对象调用了同步,同步锁就是该对象的引用
单例模式的线程安全问题
懒汉式特点:对象延迟加载,多线程访问时存在安全隐患;可以加同步来解决。同步过程中判断锁会降低效率,而同步函数每一条线程访问都会有判断锁的过程;使用同步代码块二次判断,用判断变量来替代判断锁,只需判断一次锁,稍微提高了执行效率由于是静态同步,所以懒汉式中的同步锁是本类对象的字节码文件
//饿汉式 class Single { private static final Single s=new Single();//有final修饰 private Single(){} public static Single getInstance() { return s; } } //懒汉式 class Single { private static Single s =null;//无final修饰 private Single(){} // public static Single getInstance()//延迟加载,多个线程并发访问时可能引发安全问题 // public static synchronized Single getInstance()使用同步函数,多了一步判断锁的过程,多线程时较为低效 public static Single getInstance() //使用同步代码块 { if (s==null)//减少判断锁的次数,稍微提高效率 { synchronized(Single.class)//静态同步的锁 { if(s==null) s=new Single(); } return s; } } }
线程死锁
死锁的条件:同步中嵌套同步,同步之间的调用,由于每个同步只有一个对应的锁,相互嵌套时同时持有两个锁才会执行,一旦两个同步都持有一个对方的锁无法执行也无法释放,就会导致线程死锁。这种情况应避免发生死锁示例:
class Test implements Runnable { private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if (flag) { synchronized(MyLock.a) { System.out.println("if.....a"); synchronized(MyLock.b) { System.out.println("if....b"); } } } else { synchronized(MyLock.b) { System.out.println("else....b"); synchronized(MyLock.a) { System.out.println("else......a"); } } } } } class MyLock { static Object a= new Object(); static Object b= new Object(); } class DeadLock { public static void main(String[] args) { Thread t1=new Thread(new Test(true)); Thread t2=new Thread(new Test(false)); t1.start(); t2.start(); } }
相关文章推荐
- mongo的持久化之Journaling
- hdu1839(二分+优先队列,bfs+优先队列与spfa的区别)
- windows driver 的入门方法
- mysql 事件
- 浏览器页面传值跳转
- Qt之任务栏系统托盘图标
- 银行业务学习之道:信用卡的具体功能
- 切换上下文,阻塞,内存同步
- 零点起飞学C#
- Android扩展:一个自动findViewById的小工具
- 在某网站的信息上,深感baidu快照的强大
- Maven学习笔记(二)---Myeclipse配置maven
- 成为开发者的第一步 微信开发
- Ubuntu 下安装MongoDB
- Cocos2d-x教程 Lua脚本(2) Mac系统下搭建Lua的编码环境
- java枚举类型enum的使用
- 让ie+6以上浏览器支持圆角的方法
- IOS中Json解析的四种方法
- 获取电信光猫超级用户密码
- poj1129_Channel Allocation