java 线程安全问题的解决办法 和死锁

2018-03-08  本文已影响0人  发光驴子

线程安全问题的解决办法

线程 安全问题的解决方案:sun提供了线程同步机制让我们解决这类问题的。

java线程同步机制的方式:
方式一:同步代码块

        同步代码块的格式:
            
            synchronized(锁对象){
                需要被同步的代码...
            }

同步代码块要注意事项:
1. 任意的一个对象都可以做为锁对象。
2. 在同步代码块中调用了sleep方法并不是释放锁对象的。
3. 只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率的。
4. 多线程操作的锁 对象必须 是唯一共享 的。否则无效。

    class SaleTicket extends Thread{
 static int num = 50;//票数  非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的。
 
 static Object o = new Object();

 public SaleTicket(String name) {
    super(name);
}

@Override
public void run() {
    while(true){
        //同步代码块
        synchronized ("锁") {//任意的一个对象都可以做为锁对象。对象为Static,但String特殊,因为字符串就是在字符串常量池中。              
            if(num>0){
                System.out.println(Thread.currentThread().getName()+"售出了第"+num+"号票");
                try {
                    Thread.sleep(100);//在同步代码块中调用了sleep方法并不是释放锁对象的。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                num--;
            }else{
                System.out.println("售罄了..");
                break;
            }
        }
        
    }
}   


} 


public class Thread_02 {

public static void main(String[] args) {
    String s =new String("abc");
    String str1 = "abc"; 
    System.out.println(str1 ==s);
    //创建三个线程对象,模拟三个窗口
    SaleTicket thread1 = new SaleTicket("窗口1");
    SaleTicket thread2 = new SaleTicket("窗口2");
    SaleTicket thread3 = new SaleTicket("窗口3");
    //开启线程售票
    thread1.start();
    thread2.start();
    thread3.start();
    
}

  }

方式二:同步函数
同步函数就是使用synchronized修饰一个函数。

同步函数要注意的事项 :
    1. 如果是一个非静态的同步函数的锁 对象是this对象(ps:这样会存在锁不住的情况,因为俩个对象调用同一个文件,就会出现俩个锁),如果是静态的同步函数的锁 对象是当前函数所属的类的字节码文件(class对象)。
    2. 同步函数的锁对象是固定的,不能由你来指定 的。


推荐使用: 同步代码块。
    原因:
        1. 同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定 的,不能由我们来指定。
        2. 同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数 的所有代码都被同步了。
class BankThread extends Thread{

static  int count = 5000;

public BankThread(String name){
    super(name);
}

@Override  //
public void run() {
    getMoney();//这样也锁定住,但是会造成只能一个人取完全部的钱,因为只有循环结束,才会释放锁
}   


//静态的函数---->函数所属 的类的字节码文件对象--->BankThread.class  唯一的。
public static synchronized  void getMoney(){
    while(true){            
            if(count>0){
                System.out.println(Thread.currentThread().getName()+"取走了1000块,还剩余"+(count-1000)+"元");
                count= count - 1000;
            }else{
                System.out.println("取光了...");
                break;
            }
        
    }
}

 }


  public class Demo1 {

public static void main(String[] args) {
    //创建两个线程对象
    BankThread thread1 = new BankThread("老公");
    BankThread thread2 = new BankThread("老婆");
    //调用start方法开启线程取钱
    thread1.start();
    thread2.start();
    
    
}

}       

出现线程安全问题的根本原因:
1. 存在两个或者两个以上 的线程对象,而且线程之间共享着一个资源。
2. 有多个语句操作了共享资源。

线程的死锁

/*
 * java 中同步机制解决了线程安全问题,但是同时引发死锁现象
 * 
 * 死锁现象:就是 俩个或者俩个以上线程,共同调用俩个或者以上的资源,发生共同等待的状态
 * 
 * 死锁现象的出现的根本原因:
 * 1.存在俩个或者俩个以上的线程
 * 2.存在俩个或者俩个以上的共享资源
 * 
 * 死锁现象的解决方案:没有方案,只能尽量避免发生而已

*/

class DeadLock extends Thread{
    public DeadLock(String name){
        super(name);
    }

    public void run(){
        if("张三".equals(Thread.currentThread().getName())){
            synchronized ("遥控器") {
                System.out.println("张三拿到了遥控器,准备去拿电池!!");
                synchronized ("电池") {
                    System.out.println("张三拿到了遥控器和电池,开始吹空调");
                }
            }
        
        }else if("李四".equals(this.getName())){
            synchronized ("电池") {
                System.out.println("李四拿到了电池,准备去那遥控器");
                synchronized ("遥控器") {
                    System.out.println("李四拿到了遥控器和电池,开始吹空调");
                }
            }
        
        }
    }
}
public class Thread_04 {
    public static void main(String[] args) {
            DeadLock l1=new DeadLock("张三");
        DeadLock l2=new DeadLock("李四");
        l1.start();
        l2.start();
}

}
上一篇下一篇

猜你喜欢

热点阅读