Java單例模式的學習總結

1.單例模式的概念:

參考網址:http://www.importnew.com/21866.html
https://blog.csdn.net/u014672511/article/details/79774847
http://www.importnew.com/18872.html
http://www.importnew.com/18872.html
單例模式是指在應用整個生命週期內只能存在一個實例。它能夠避免對象的重複創建,減少創建實例的系統開銷,節省內存。

2.如何實現單例模式

我這裏重點講的是使用java中的Synchronized。

synchronized 關鍵字,代表這個方法加鎖,相當於不管哪一個線程(例如線程A),運行到這個方法時,都要檢查有沒有其它線程B(或者C、 D等)正在用這個方法(或者該類的其他同步方法),有的話要等正在使用synchronized方法的線程B(或者C 、D)運行完這個方法後再運行此線程A,沒有的話,鎖定調用者,然後直接運行。它包括兩種用法:synchronized 方法和 synchronized 塊。

synchronized是Java中的關鍵字,是一種同步鎖
1.無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
2.每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
3.實現同步是要很大的系統開銷作爲代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制。


3.Synchronized的使用

3.1修飾一個代碼塊

知識點重點:
        每個對象只有一個鎖(lock),而synchronized只鎖定對象,所以在多線程編程的時候,我們要讓每個線程訪問的不是同一個對象,不然的話就會出現線程阻塞的情況,只有當Thred1執行完後,Thread2纔會去執行

例子:

/**
 * 同步線程
 */
class SyncThread implements Runnable {
   //static聲明的變量會放到方法區內存裏面,只會保存一份不會被重複創建
   private static int count;
 
   public SyncThread() {
      count = 0;
   }
 
   public  void run() {
      synchronized(this) {
         for (int i = 0; i < 5; i++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }
 
   public int getCount() {
      return count;
   }
}

新建一個類Thread_tongbu.java用來做測試,放入以下代碼:

public class Thread_tongbu {
    public static void main(String[] args) {
        SyncThread syncThread = new SyncThread();
        Thread thread1 = new Thread(syncThread, "SyncThread1");
        Thread thread2 = new Thread(syncThread, "SyncThread2");
        thread1.start();
        thread2.start();
    }
}

結果如下:

SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

Process finished with exit code 0

這裏我們會發現線程2被阻塞了,等到線程1執行完才執行。
因爲在執行synchornized代碼塊時會鎖定當前的對象,只有執行完該代碼塊才能釋放該對象鎖,下一個線程才能執行並鎖定該對象。
當兩個併發線程(thread1和thread2)訪問同一個對象(syncThread)中的synchronized代碼塊時,在同一時刻只能有一個線程得到執行,另一個線程受阻塞,必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。Thread1和thread2是互斥的。

要解決上訴問題,我們必須要讓線程執行的不是同一個對象,因爲每個對象只有一個鎖,誰拿到誰用,所以我們可以對代碼做以下修改:

Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
thread1.start();
thread2.start();

結果:

SyncThread1:0
SyncThread2:1
SyncThread1:2
SyncThread2:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread1:7
SyncThread1:8
SyncThread2:9

不是說一個線程執行synchronized代碼塊時其它的線程受阻塞嗎?爲什麼上面的例子中thread1和thread2同時在執行。這是因爲synchronized只鎖定對象,每個對象只有一個鎖(lock)與之相關聯,而上面的代碼等同於下面這段代碼:

SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();

這時創建了兩個SyncThread的對象syncThread1和syncThread2,線程thread1執行的是syncThread1對象中的synchronized代碼(run),而線程thread2執行的是syncThread2對象中的synchronized代碼(run);我們知道synchronized鎖定的是對象,這時會有兩把鎖分別鎖定syncThread1對象和syncThread2對象,而這兩把鎖是互不干擾的,不形成互斥,所以兩個線程可以同時執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章