程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 0037 Java學習筆記-多線程-同步代碼塊、同步辦法、同步鎖

0037 Java學習筆記-多線程-同步代碼塊、同步辦法、同步鎖

編輯:關於JAVA

0037 Java學習筆記-多線程-同步代碼塊、同步辦法、同步鎖。本站提示廣大學習愛好者:(0037 Java學習筆記-多線程-同步代碼塊、同步辦法、同步鎖)文章只能為提供參考,不一定能成為您想要的結果。以下是0037 Java學習筆記-多線程-同步代碼塊、同步辦法、同步鎖正文


什麼是同步

  • 在上一篇0036 Java學習筆記-多線程-創立線程的三種方式示例代碼中,完成Runnable創立多條線程,輸入中的後果中會有錯誤,比方一張票賣了兩次,有的票沒賣的狀況,由於線程對象被多條線程訪問,一條線程在執行一個循環的進程中被中綴,下一個線程則呈現錯誤
  • 因而,線程義務中能夠惹起錯誤的中央該當被一次執行終了

同步代碼塊

  • 用同步代碼塊改寫下面的代碼
package testpack;

public class Test1  { 
    public static void main(String[] args){ 
        System.out.println("如今是主線程: "+Thread.currentThread()); 
        System.out.println("上面新建兩個線程");
        A a=new A(500); 
        new Thread(a,"線程A").start(); 
        new Thread(a,"線程B").start();
        new Thread(a,"線程C").start();
    }
}
class A implements Runnable{
    private int tickets;
    A (int tick){
        tickets=tick;
    }
    private Object obj=new Object();              //同步監視器
    public void run() {
        synchronized(obj){                        //同步代碼塊
            for (;tickets>0;tickets--) {
                System.out.println("以後線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");
                try{
                    Thread.sleep(1);              //讓以後線程暫停1毫秒,其他線程也不能執行該同步代碼塊
                }catch(InterruptedException ex){
                    ex.printStackTrace();
                }
                if (tickets==1){
                    System.out.println("票已賣完,以後線程是: "+Thread.currentThread());
                }
            }
        }
        
    }
}
  • 同步監視器,就是一個普通的對象,好像一把鎖,只要取得了同步監視器的線程才干執行同步代碼塊。
  • 同步代碼塊執行一次終了後,將會釋放鎖,接上去是這條線程拿到同步鎖,還是其他其他線程,則不一定,依據線程調度而定,但是在同步代碼塊執行進程中,不會被中綴,一個同步義務會被一次執行終了

同步辦法

  • 在同步代碼塊中,synchonized關鍵字在run()辦法外部,修飾的是一段代碼,也可以用來修飾run()辦法,也就是同步辦法
  • synchronized不只可以修飾run()辦法,還可以修飾其他辦法,只需是需求一次同步完成的義務,然後再在run()辦法中被調用
  • 同步辦法中有一個隱式的同步監視器,就是this,也就是調用run()辦法(或同步辦法)的這個對象
  • 還是下面的實例,用同步辦法改寫
package testpack;

public class Test1  { 
    public static void main(String[] args){ 
        System.out.println("如今是主線程: "+Thread.currentThread()); 
        System.out.println("上面新建兩個線程");
        A a=new A(500);
        new Thread(a,"線程A").start();
        new Thread(a,"線程B").start();
        new Thread(a,"線程C").start();
    }
}
class A implements Runnable{
    private int tickets;
    A (int tick){
        tickets=tick;
    }
    public synchronized void run() {                                    //同步辦法
            for (;tickets>0;tickets--) {
                System.out.println("以後線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");
                try{
                    Thread.sleep(1);
                }catch(InterruptedException ex){
                    ex.printStackTrace();
                }
                if (tickets==1){
                    System.out.println("票已賣完,以後線程是: "+Thread.currentThread());
                }
            }
        
    }
}

釋放同步監視器

  • 以後線程的同步義務(同步辦法、同步代碼塊)執行終了
  • 在同步義務中,遇到break、return,終止了同步義務
  • 在同步義務中,呈現Error、Exception等,招致同步義務完畢
  • 在同步義務中,執行了同步監視器對象的wait()辦法,則以後線程暫停,並釋放同步監視器
  • 不會釋放同步監視器的狀況:
    • 同步義務中,調用Thread.sleep()、Thread.yield()辦法來暫停以後線程的執行
    • 同步義務中,其他線程調用了該線程的suspend()辦法將該線程掛起

同步鎖

  • 除了可以用new Object()和this作同步監視器往外,還可以定義專門的同步鎖,且功用愈加強
  • Lock接口
    • ReentrantLock完成類
  • ReadWriteLock
    • ReentrantReadWriteLock完成類
    • ReentrantReadWriteLock.ReadLock
    • ReentrantReadWriteLock.WriteLock
  • StampedLock
  • 示例:用ReentrantLock改寫下面的代碼
package testpack;

import java.util.concurrent.locks.ReentrantLock;

public class Test1  { 
    public static void main(String[] args){ 
        System.out.println("如今是主線程: "+Thread.currentThread()); 
        System.out.println("上面新建兩個線程");
        A a=new A(50);
        new Thread(a,"線程A").start();
        new Thread(a,"線程B").start();
        new Thread(a,"線程C").start();
    }
}
class A implements Runnable{
    private final ReentrantLock lock=new ReentrantLock();    //定義一個同步鎖
    private int tickets;
    A (int tick){
        tickets=tick;
    }
    public void run() {
            lock.lock();                                     //加鎖
            for (;tickets>0;tickets--) {
                System.out.println("以後線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");
                if (tickets==1){
                    System.out.println("票已賣完,以後線程是: "+Thread.currentThread());
                }
            }
            lock.unlock();                                    //釋放鎖
    }
}

死鎖

  • 兩個線程各拿一把鎖,下一步運轉都需求對方手裡那把鎖,但都拿不到,則形成死鎖,順序不能持續執行
package testpack;
public class Test1  { 
    public static void main(String[] args){ 
        DeadLock dl=new DeadLock();
        new Thread(dl).start();
        dl.init();
    }
}
class DeadLock implements Runnable {
    A a=new A();
    B b=new B();
    public void init(){
        a.a1(b);
        System.out.println("進入主線程");
    }
    public void run(){
        b.b1(a);
        System.out.println("進入子線程");
    }
}
class A {
    public synchronized void a1(B b){
        System.out.println("以後線程是:"+Thread.currentThread().getName()+" ,正在執行a1()");
        try{
            Thread.sleep(10);
        }catch(InterruptedException ex){
            ex.printStackTrace();
        }
        System.out.println("以後線程是:"+Thread.currentThread().getName()+" ,預備調用b2()");
        b.b2();   //b2辦法是同步辦法,調用該辦法要對調用的對象b加鎖
    }
    public synchronized void a2(){
        System.out.println("這是a2()辦法");
    }
}
class B{
    
    public synchronized void b1(A a){
        System.out.println("以後線程是:"+Thread.currentThread().getName()+" ,正在執行b1()");
        try{
            Thread.sleep(10);
        }catch(InterruptedException ex){
            ex.printStackTrace();
        }
        System.out.println("以後線程是:"+Thread.currentThread().getName()+" ,預備調用a2()");
        a.a2();   //a2辦法是同步辦法,調用該辦法要對調用的對象a加鎖
    }
    
    public synchronized void b2(){
        System.out.println("這是b2()辦法");
    }
}
  • 下面在調用a.a2()和b.b2()辦法時,辨別要對a對象和b對象加鎖,但這時,a、b對象的鎖都在對方手裡,形成兩個線程阻塞

其他

  • 可變類的線程平安是以降低順序的運轉效率為代價的
  • 不要對線程平安類的一切辦法都停止同步,只對那些改動共享資源的辦法停止同步
  • 假如一個類有單線程和多線程運轉環境,那麼應該提供兩種版本,就是StringBuilder(單線程)和StringBuffer(多線程)一樣
    
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved