黑马程序员--Java基础--多线程安全问题

来源:互联网 发布:js string转jsonarray 编辑:程序博客网 时间:2024/05/29 16:47

----------------------Android培训Java培训、期待与您交流! ---------------------- 

多线程安全问题

导致线程安全问题出现的原因:

·多个线程访问出现延迟。

·线程随机性。

注:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。 

 

解决线程安全问题:同步

多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。

同步的两种形式:1,同步函数  2,同步代码块

同步代码块

/*简单的卖票程序:多个窗口同时买票。通过分析,发现,打印出0,-1,-2等错票。多线程的运行出现了安全问题。问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。Java对于多线程的安全问题提供了专业的解决方式。就是同步代码块。synchronized(对象){需要被同步的代码}对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。火车上的卫生间---经典。同步的前提:1,必须要有两个或者两个以上的线程。2,必须是多个线程使用同一个锁。必须保证同步中只能有一个线程在运行。好处:解决了多线程的安全问题。弊端:多个线程需要判断锁,较为消耗资源*///通过同步的方式实现多窗口买票,解决了0,-1,-2等错票的问题class Ticket2 implements Runnable//定义类实现Runnable接口{private  int tick = 1000;Object obj = new Object(); //锁可以是任意对象,所以任意对象调用的方法一定定义在Object类中//覆盖Runnable接口中的run方法 ,将买票过程的代码存放在该run方法中public void run(){while(true){synchronized(obj) //同步代码块{if(tick>0){//try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);}}}}}class  TicketDemo2{public static void main(String[] args) {Ticket t = new Ticket();//创建一个Runnable接口的子类对象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();}}

同步函数

/*需求:银行有一个金库,有两个储户分别有300元,每次存100,存3次目的:该程序是否有安全问题,如果有,如何解决如何找到问题:1,明确哪些代码时多线程运行代码。2,明确共享数据3,明确多线程运行代码中哪些语句是操作共享数据的同步的两种形式:1,同步函数  2,同步代码块  * */class Bank{private int sum;//定义同步函数public synchronized void  add(int num){sum=sum+num;System.out.println("sum is "+sum);}}class Cus implements Runnable{private Bank b=new Bank();public void run() {for(int x=0;x<3;x++){b.add(100);}}}public class ThreadDemo {public static void main(String[] args) {Cus c=new Cus();Thread t1=new Thread(c);Thread t2=new Thread(c);t1.start();t2.start();}}


 

死锁(DeadLock)
是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象。
此时称系统处于死锁状态,这些永远在互相等待的线程称为死锁线程。
 

//买票程序死锁/* * 买票程序死锁死锁。同步中嵌套同步。*/class Ticket3 implements Runnable{private  int tick = 100;Object obj = new Object();boolean flag = true;public  void run(){if(flag){while(true){synchronized(obj){show();}}}elsewhile(true)show();}public synchronized void show(){synchronized(obj){if(tick>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);}}}}public class DeadLockDemo {public static void main(String[] args) {Ticket3 t = new Ticket3();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.start();try{Thread.sleep(10);}catch(Exception e){}t.flag = false;t2.start();}}

产生死锁的四个必要条件是: 
1:互斥条件:资源每次只能被一个线程使用。如前面的“线程同步代码段”。
2:请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
3:不剥夺条件:进程已获得的资源,在未使用完之前,无法强行剥夺。
4:循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。


 

----------------------Android培训Java培训、期待与您交流! ----------------------