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對象,而這兩把鎖是互不干擾的,不形成互斥,所以兩個線程可以同時執行。