黑马程序员_多线程安全问题
来源:互联网 发布:java zip压缩 编辑:程序博客网 时间:2024/05/17 06:15
------- android培训、java培训、期待与您交流! ----------
多线程安全问题
第一部分
1、多线程安全问题的描述
在卖票程序中多线程安全问题的描述:当4个线程在分别执行程序的时候,0线程进入程序进行判断tick>0;刚判断完条件,这时候0线程就卧倒下了,卧倒就是0线程具备执行的资格但是执行权被其他的线程给强走了,换句话说就是cpu切换到其他人那边去了;这是1线程就获得了执行权,1线程判断条件tick>0,是满足条件的,然后依次类推都是有可能出现这些情况,也就是说4个线程都已经卧倒了,但是这是cpu这是切换到了0线程身上了,这是0线程就直接向下执行了,这时0线程输出的票是1号票,但是这时1线程输出的是0号票,2线程输出的是-1号票,3线程输出的是-2号票,按照人们生活常理是没有0号票还负数的票的;-->这时程序就有可能会出现安全隐患;2、用代码体现多线程安全问题
//实现Runnableclass Ticket implements Runnable{private int tick =100;//Object obj = new Object();public void run(){while(true){//synchronized(obj)//{if(tick>0){//sleep方法抛出了异常try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}System.out.println(Thread.currentThread().getName()+"sale:"+tick--);//}}}}}class TicketDemo2{public static void main(String[] args) {Ticket t = new Ticket();//创建线程;需要传一个Ticket对象;要指定run方法所属对象;//Thread(Runnable target) 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();}}3、代码运行的结果
4、问题的描述
多线程最恐慌的就是安全问题,通过分析,发现出现了0和-1号票,因此就是多线程的运行出现了安全问题,
5、问题的原因
|--当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。|--如果一个线程进来把所有的语句都执行完,然后下一个线程在进来把程序执行完,那么就没有问题了。6、解决办法
|--对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行;换句话说就是0线程在程序里面执行,1线程即使拿到了执行权也不让1线程执行;那么这样就靠谱了;|--java对于多线程的安全问题提供了专业的解决方式;就是同步代码块;|--如何判断哪些代码需要同步:就要看哪些代码在操作共享数据;-->tick就是共享数据;//同步代码块synchronized(对象){需要被同步的代码}7、代码体现
//实现Runnableclass Ticket implements Runnable{private int tick =500;//需要放一个对象;Object obj = new Object();public void run(){while(true){//同步代码块synchronized(obj){if(tick>0){//sleep方法抛出了异常try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}System.out.println(Thread.currentThread().getName()+"sale:"+tick--);}}}}}class TicketDemo2{public static void main(String[] args) {Ticket t = new Ticket();//创建线程;需要传一个Ticket对象;要指定run方法所属对象;//Thread(Runnable target) 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();/*Ticket t1 = new Ticket();Ticket t2 = new Ticket();Ticket t3 = new Ticket();Ticket t4 = new Ticket();t1.start();t2.start();t3.start();t4.start();*/}}8、运行结果
现在就是4个线程共同操作一个共享数据,并且没有出现0和负数的情况;
9、同步原理
|--四个线程,这时有两个标志位,一个是0,一个是1,当0线程获取到cpu执行权时,判断标志位是1,进入同步代码快中,0线程进入以后,就把标志位恩恩1变成了0;把锁给关上了,然后0线程就判断if语句,满足条件,就开始读取,这时读取到了sleep语句,这是0线程就处于卧倒状态,这时1线程就进入懂啊了语句中,1线程就判断标志位是0,-->但是1线程是进不来的,这时0线程进醒了,就继续执行语句,出了同步,这是0线程就又做了一件事,就是把标志位的0置成了1;这时3线程抢到了执行权,这时3线程就把标志位改成了0;synchronized(obj)-->这个是一个锁,只有拿到了这个锁才可以进入到程序中执行,否则就一直等;|--同步经典例子:火车上卫生间|--对象如同锁,持有锁的线程可以在同步中执行;没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁;10、同步前提
|--必须要有两个或者两个以上的线程;|--必须是多个线程使用同一个锁;11、同步好处和弊端
好处:解决了多线程的安全问题;弊端:多个线程需要判断锁,较为消耗资源;
第二部分
1、同步函数的描述
需求:银行有个金库,有两个储户分别往里面存钱,每次存100,分别存3次;
问题的描述:当储户在存钱的时候,第一个储户出了100元,但是没有立即执行输出语句,而是卧倒了,这是又来了一个储户,来存钱,存了100后,变成了200元,这时就执行了输出语句,打印了200元,而没有打印100;这就是出现了安全问题;
如何找问题:
|--明确哪些代码是多线程运行代码;|--明确共享数据;|--明确多线程运行代码中,哪些语句是操作的是共享数据;
2、同步函数
同步有两种表现形式:
|--同步代码:把同步放在代码中;|--同步函数:把同步作为修饰符放在函数上;3、同步函数的锁是this
|--如果卖票的程序在函数上使用同步的话,那么是不OK的,这样输出的是只有0线程一直在运行,把锁就一直锁起来了,其他的线程就没有运行;|--同步函数用的是哪一个锁呢?
|--函数需要被对象调用,那么函数都有一个所属对象应用,就是this,所以同步函数使用的锁是this;验证:
|--当同步代码块里面的锁的对象是obj的时候,同步函数里面的锁是this的时候,运行的结果是线程0和线程1交替运行,而且还出现了不同步的现象;
|--当同步代码块里面的锁的对象是this的时候,同步函数里面的锁是this的时候,运行的结果只有线程1运行;
|--由此可见,同步函数里面的锁是this锁;
4、代码体现
//卖票的程序//线程0是同步代码块,线程1是同步函数;class Ticket implements Runnable{private int tick =100;Object obj = new Object();//boolean型的标记boolean flag = true;public void run(){//是true的话if(flag){while(true){//同步代码块synchronized(this){if(tick>0){try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}//同步代码快System.out.println(Thread.currentThread().getName()+"--code--"+tick--);}}}}//如果是false的话elsewhile(true)show();}//同步函数public synchronized void show()//这个锁是this;{if(tick>0){try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}//同步函数System.out.println(Thread.currentThread().getName()+"--show--"+tick--);}}}class ThisLockDemo{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();//让主线程停10毫秒try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}//把flag改为false,并开启t2t.flag =false;t2.start();//t3.start();//t4.start();}}5、运行结果
由此可见,同步函数用的是this锁;
第三部分
1、同步静态函数描述
|--通过验证法发现同步静态函数出现了不同步的现象;也就是说静态函数用的锁不是this锁;其实静态方法中是没有this的,因为静态中是没有对象的;
|--静态静内存后,内存中没有本类对象,但是一定有该类所属的字节码文件对象;
|--格式是:类名.class;该对象的类型是Class;
2、通过代码展现
class Ticket implements Runnable{private static int tick =100;Object obj = new Object();boolean flag = true;public void run(){if(flag)while(true){//该类所属的字节码文件对象;synchronized(Ticket.class){if(tick>0){try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}System.out.println(Thread.currentThread().getName()+"--code--"+tick--);}}}elsewhile(true)show();}public static synchronized void show(){if(tick>0){try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}System.out.println(Thread.currentThread().getName()+"--show--"+tick--);}}}class StaticMethodDemo{public static void main(String[] args) {Ticket t = new Ticket();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.start();try{Thread.sleep(10);}catch (Exception e){System.out.println(e.toString());}t.flag =false;t2.start();}}3、运行结果
当在静态同步函数,发现其的对象不是this锁了,而是该类所属的字节码文件对象,类名.class;
第四部分
我的总结
|--在同步代码块里面用的锁是任意对象,|--在同步函数里面用的锁是this;|--在静态同步函数上用的锁是该类所属的字节码文件对象,格式:类名.class;|--想要解决多线程的安全问题,就要先明确同步的两个前提:是不是有多个线程,是不是用的是同一把锁;
0 0
- 黑马程序员_多线程安全问题
- [黑马程序员]多线程_进出解决安全问题
- 黑马程序员_多线程安全问题的解决方法
- 黑马程序员---多线程及其安全问题
- 黑马程序员_java多线程安全问题
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- spring整合消息队列rabbitmq
- gpio_direction_output 和 gpio_set_value用法的区别
- RxJava的Subscriber出现onError时
- 【架构】关于RabbitMQ
- NFS(网络文件系统)简述及使用
- 黑马程序员_多线程安全问题
- android ImageView点击事件如何监听
- 小数化成最简式分数
- RabbitMQ消息队列(九):Publisher的消息确认机制
- 简单sql问题
- 监视器 RUIGE瑞鸽高清监视器TL-S1700HD
- 运动目标检测、阴影检测及目标跟踪中用得到的标准测试视频下载(大量IBM提供视频)
- 多层感知机(Multilayer Perceptron)
- Android中Toast不显示的解决方案