java基礎專欄—ThreadSafe

ThreadSafe

多線程併發

public class Tickets implements Runnable{
    private int ticket = 100;
  	
  	public void run(){
        while(true){
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
            }
        }
    }
}
pubilc static void main(String[] args){
    Tickets ts = new Ticket();
  	
  	Thread t0 = new Thread(ts);
  	Thread t1 = new Thread(ts);
  	Thread t2 = new Thread(ts);
  
  	t0.start();
  	t1.start();
  	t2.start();
}

同步代碼塊解決線程問題:synchronized(Object obj){線程要操做的代碼塊}java

private Object obj = new Object();
public void run(){
		while(true){
          	synchronized(obj){
               if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
        	    } 
            }   
        }
	}

同步對象:任意對象,對象監聽器多線程

沒有鎖的線程不能執行只能等待,碰見同步代碼塊,併發

  • 判斷對象鎖還有沒有
  • 有,拿走,等執行完成才放回去
  • 沒有就只有等
  • 將線程共享部分抽取出來
private int ticket = 100;
public void run(){
		while(true){
          	pay();
            }   
        }
	}
public static synchronized void pay(){
	if(ticket > 0){]
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
}
//在同步方法中,對象鎖是this。可是在靜態方法中,對象鎖不是this,this屬於對象,優先於static,是本類本身.class

Lock

​ 在線程中,只有出了同步代碼塊纔會釋放對象鎖,可是要是出現了異常就不會釋放了。因此在jdk5之後就使用Lock接口this

public void lock()

public void unlock()

死鎖問題

鎖的嵌套出現了互鎖線程

  • 確保鎖惟一
    • 構造方法私有,只能經過靜態方法來調用,且不可修改
public class lockA{
  	public static final LockA lockA = new LockA(); 
  	
  	private LockA(){
      
  	}
}

public class lockB{
  	public static final LockB lockB = new LockB(); 
  	
  	private LockB(){
      
  	}
}

public class DeadLock implements Runnable{
    private int i = 0;
  
  	public void run(){
        while(ture){
            if(i%2 == 0){
                //先進入A同步,在進入B同步
              	synchronized(LockA.locka){
                    System.out.println("if...locka");
                  	synchronized(LockB.lockb){
                        System.out.println("else...lockb");
                    }
                }
            }else{
                synchronized(LockB.lockb){
                    System.out.println("if...lockb");
                  	synchronized(LockA.locka){
                        System.out.println("else...locka");
                    }
                }
            }
        }
    }
}

線程間通訊

​ 多個線程操做同一個數據,可是操做的動做可能並不相同,經過必定的手段將各個線程有效的利用,既--等待喚醒機制code

  • public void wait()釋放正在執行的線程的執行權,放到存儲池對象

  • public void notify()喚醒在線程池中wait()的線程,一次喚醒一個,並且是任意的。接口

  • public void notifyAll(),喚醒在線程池中全部的wait()線程喚醒get

  • [x] 線程之間是否是全部的數據都鎖上了同步

  • [x] 是否是用的同一個鎖

public class Resource{
    public String name;
  	public String sex;
  	public boolean flag;//喚醒標識
  
  	public Resource(String name,String sex){
        this.name = name;
    }
}

public class InputThread implements Runnable{
    private Resource r = null;
  	public InputThread(Resource r){
        this.r = r;
    }
  	public void run(){
      	int i = 0; 
        while(true){
            synchronized(r){
              	if(r.flag){
                    try{
                      //必須是鎖對象調用
                        r.wait();
                    }catch(Exception ex){
                        System.out.println(ex.getMessage());
                    }
                }
          		if(i%2 == 0){
                	r.name = "張三";
              		r.sex = "男";
            	}else{
                    r.name = "lisi";
              		r.sex = "nv";
                }
          	i++;
            //執行完成,將標識修改,並喚醒對方。
            r.flag = true;
            r.notify();
            }
        }
    }
}

public class OutputThread{
    private Resource r = null;
  	public void run(){
      //使用同一個對象鎖
      	synchronized(r){
      		while(true){
              	if(r.flag){
                    try{
                      //必須是鎖對象調用
                        r.wait();
                    }catch(Exception ex){
                        System.out.println(ex.getMessage());
                    }
            	System.out.println(r.name); 
                //執行完成,將標識修改,並喚醒對方。
                r.flag = false;
                r.notify();
        	}
        }
    }
  	public OutputThread(Resource r){
        this.r = r;
    }
}

public class ThreadDemo{
    public static void main(String[] args){
      	Resource r = new Resource();
        InputThread int = new InputThread(r);
      	OutputThread outt = new OutputThread(r);
		
      	Thread in = new Thread(in);
      	Thread out = new Thread(out);
    }
}

爲何是Object的方法

​ 對於線程來講,要同步必須操做同一個鎖對象才能夠,若是是使用各自來作本身的線程喚醒對象就不能實現同一個鎖對象,而且對於實現類來講,調用者是誰?

​ ==全部的線程的等待喚醒必須是鎖對象調用,調用者是誰?任何方法都須要被調用,本類線程類是沒有wait方法的,只有調用父類的super(),可是父類也沒有這個方法,調用這個的鎖對象是誰就由誰來調用,因此,同步的等待喚醒方法都是Object類的方法==

相關文章
相關標籤/搜索