Java學習28 2020-03-15

內容

1.synchronized工作原理
2.synchronized修飾方法
3.一個小面試題(輸出結果目前看不懂)
4.類鎖
5.死鎖

一.synchronized的工作原理

synchronized(this){}
t1線程執行到此處,遇到了synchronized關鍵字,就會去找this的對象鎖,如果找到this對象鎖,則進入同步語句塊中執行程序,當同步語句塊中的代碼執行結束之后,t1線程歸還this的對象鎖。
在t1線程執行同步語句塊的過程中,如果t2線程也過來執行這些代碼,也遇到synchronized關鍵字,所以也去找this的對象鎖,但是該對象鎖被t1線程持有,只能在這等待this對象的歸還

二.synchronized修飾方法

使用示例

    public  synchronized void withdraw(double money) {

            double after = balance - money;
            
            //延遲
            try{Thread.sleep(1000);}catch(Exception e) {}
            
            //更新余額
            this.setBalance(after); 
       
        
    }

當synchronized關鍵字添加到成員方法上的時候,線程拿走的也是this的對象鎖。但是這種方式不推薦,不如前面那一種同步的更精細

三.一個小面試題(輸出結果目前看不懂)

/*
 * 面試題
 */


public class 測試程序   {                                                                                                             
                                                                                                                        
    public static void main(String[] args) throws InterruptedException  {
   
        //創建mc對象
        MyClass mc = new MyClass();
                
        Processor p = new Processor(mc);
        
        //創建線程t1,t2并命名
        Thread t1 = new Thread(p);
        t1.setName("t1");
        
        Thread t2 = new Thread(p);
        t2.setName("t2");
        
        //啟動線程
        t1.start();
        
        //延遲(保證t1先啟動,并執行run)
        Thread.sleep(1000);
        
        t2.start();
    }

   
    
}

//創建線程
class Processor implements Runnable
{
    MyClass mc;
    
    Processor(MyClass mc){
        this.mc = mc;
    }
    
    public void run() {
        
        //如果是t1線程,就執行m1
        if(Thread.currentThread().getName().equals("t1"));{
            mc.m1();
        }
        
        //如果是t2線程,就執行m2
        if(Thread.currentThread().getName().equals("t2")) {
            mc.m2();
        }
    }
}
class MyClass{
    
    public synchronized void m1() {
        
        //休眠
        try {
            Thread.sleep(2000);
        }catch(Exception e) {}
        
        System.out.println("m1");
        
        
    }
    
    //m2方法會等m1方法結束,t1,t2共享同一個mc,并且m1和m2方法上都有synchronized
    public synchronized void m2() {
        System.out.println("m2");
    }
}


上面這個程序本應該輸出
m1
m2
但是實際上輸出了
m1
m1
m2
想了好久也不知道什么原因。

剛才講的是對象鎖,下面講類鎖

四.類鎖

1.如何使用

synchronized添加到靜態方法上,線程執行此方法的時候會找類鎖

2.使用示例

public class 測試程序   {                                                                                                             
                                                                                                                        
    public static void main(String[] args) throws InterruptedException  {
   
        Thread t1 = new Thread(new Processor());
        Thread t2 = new Thread(new Processor());
        
        t1.setName("t1");
        t2.setName("t2");
        
        t1.start();
        
        //延遲,保證t1先執行
        Thread.sleep(1000);
        
        t2.start();
        
    }

   
    
}

//創建線程
class Processor implements Runnable
{
    
    
    public void run() {
        
        if("t1".equals(Thread.currentThread().getName())) {
            MyClass.m1();
        }
        if("t2".equals(Thread.currentThread().getName())) {
            MyClass.m2();
        }
        
    }
}
class MyClass{
    
    //synchronized添加到靜態方法上,線程執行此方法的時候會找類鎖
    public synchronized static void m1() {
        try {
            Thread.sleep(10000);
        }catch(Exception e) {}
        System.out.println("m1...");
        
    }
    
    //不會等m1結束,因為該方法沒有被synchronized修飾
    /*public static void m2() {
        System.out.println("m2...");
    }
    */
    //這個m2方法會等m1方法結束之后才執行,因為該方法有synchronized
    //線程執行該代碼需要類鎖,而類鎖只有一個
    public synchronized static void m2() {
        System.out.println("m2...");
    }
}

就會輸出
m1...
m2...

五.死鎖

public class 測試程序   {                                                                                                             
                                                                                                                        
    public static void main(String[] args) throws InterruptedException  {
   
        Object o1 = new Object();
        Object o2 = new Object();
        
        Thread t1 = new Thread(new T1(o1,o2));
        Thread t2 = new Thread(new T2(o1,o2));
        
        t1.start();
        t2.start();
        
    }

   
    
}

class T1 implements Runnable{
    
    Object o1;
    Object o2;
    
    T1(Object o1,Object o2){
        this.o1 = o1;
        this.o2 = o2;
    }
    
    public void run() {
        synchronized(o1) {
            try{Thread.sleep(1000);}catch(Exception e) {}
            synchronized(o2) {
                
            }
        }
    }
}

class T2 implements Runnable{
    
    Object o1;
    Object o2;
    
    T2(Object o1,Object o2){
        this.o1 = o1;
        this.o2 = o2;
    }
    
    public void run() {
        synchronized(o2) {
            try {
                Thread.sleep(1000);
            }catch(Exception e) {}
            synchronized(o1) {
                
            }
        }
    }
}

這個程序就進入一個僵持狀態
t1剛鎖住o1,準備鎖o2時,o2已經被t2鎖住,此時t2還想鎖o1

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 2,986評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,482評論 1 15
  • 進程:正在執行的程序,是一個動態的過程 線程:是進程中用于控制程序執行的控制單元(執行路徑,執行情景) 進程中至少...
    寶塔山上的貓閱讀 451評論 0 1
  • 一擴展javalangThread類二實現javalangRunnable接口三Thread和Runnable的區...
    和帥_db6a閱讀 497評論 0 1
  • 一:概述 java發生線程安全的有原因有兩個因素:第一,存在共享資源(也稱臨界資源,不知道為什么取這破名字);第二...
    涂豪_OP閱讀 766評論 0 1