1琅坡、ThreadLocal
線程局部變量憔儿,是一種多線程間并發(fā)訪問(wèn)變量的解決方案噪矛,與synchronized
加鎖方式不同医清,ThreadLocal
完全不提供鎖起暮,而使用以空間換時(shí)間的手段,為每個(gè)線程提供變量的獨(dú)立副本会烙,保障線程安全负懦。
從性能上講, ThreadLocal
不具有絕對(duì)的優(yōu)勢(shì)柏腻,在并發(fā)不是很高的時(shí)候纸厉,加鎖性能會(huì)更好,但在高并發(fā)或者競(jìng)爭(zhēng)激烈時(shí)五嫂,如硬件較好颗品,用ThreadLocal
一定程度上減少鎖競(jìng)爭(zhēng)。
2、單例模式
單例模式的饑餓與懶漢模式在多線程中是不行的抛猫,性能不高且不能保證線程安全
靜態(tài)內(nèi)部類模式,推薦孩灯,最安全闺金,最可靠
public class InnerSingleton {
private static class Singleton {
private static Singleton single = new Singleton();
}
public static Singleton getInstance() {
return Singleton.single;
}
}
比較:
package demo2;
public class MySingleTon {
// 1:餓漢 一旦完成加載,就把單例初始化完成峰档,getInstance時(shí)已存在
private final static MySingleTon singleTon = new MySingleTon();
private MySingleTon() {
System.out.println("starting init single");
}
public static MySingleTon getInstance() {
return singleTon;
}
public static void main(String[] args) {
System.out.println("-------------");
MySingleTon sinle1 = MySingleTon.getInstance();
System.out.println("-------------");
MySingleTon sinle2 = MySingleTon.getInstance();
System.out.println("-------------");
MySingleTon sinle3 = MySingleTon.getInstance();
}
}
打影芷ァ:
starting init single
-------------
-------------
-------------
package demo2;
public class MySingleTon {
// 2 線程安全的 懶漢式 調(diào)用getInstance時(shí) 初始化實(shí)例
private static MySingleTon single = null;
private MySingleTon() {
System.out.println("starting init single");
}
public static MySingleTon getInstance() {
if (single == null) {
synchronized(MySingleTon.class) {
if (single == null) {
single = new MySingleTon();
}
}
}
return single;
}
public static void main(String[] args) {
System.out.println("-------------");
MySingleTon sinle1 = MySingleTon.getInstance();
System.out.println("-------------");
MySingleTon sinle2 = MySingleTon.getInstance();
System.out.println("-------------");
MySingleTon sinle3 = MySingleTon.getInstance();
}
}
打印
-------------
starting init single
-------------
-------------
public class Singleton
{
private Singleton(){ }
public static Singleton getInstance()
{
return Nested.instance;
}
//在第一次被引用時(shí)被加載
static class Nested
{
private static Singleton instance = new Singleton();
}
public static void main(String args[])
{
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2);
}
}
3、至于1讥巡、2掀亩、3這三種實(shí)現(xiàn)又有些區(qū)別:
- 第1種:餓漢式在類創(chuàng)建的同時(shí)就實(shí)例化一個(gè)靜態(tài)對(duì)象出來(lái),不管之后會(huì)不會(huì)使用這個(gè)單例欢顷,都會(huì)占據(jù)一定的內(nèi)存槽棍,但是相應(yīng)的,在第一次調(diào)用時(shí)速度也會(huì)更快抬驴,因?yàn)槠滟Y源已經(jīng)初始化完成炼七,
- 第2種,在
getInstance
中做了兩次null檢查布持,確保了只有第一次調(diào)用單例的時(shí)候才會(huì)做同步豌拙,這樣也是線程安全的,同時(shí)避免了每次都同步的性能損耗 - 第3種题暖,利用了
classloader
的機(jī)制來(lái)保證初始化instance時(shí)只有一個(gè)線程按傅,所以也是線程安全的,同時(shí)沒(méi)有性能損耗胧卤,所以一般我傾向于使用這一種唯绍。
PS1
一種通過(guò)內(nèi)部類來(lái)實(shí)現(xiàn)單例的方式,靜態(tài)內(nèi)部類只能訪問(wèn)外部類的靜態(tài)方法和靜態(tài)屬性≈μ埽現(xiàn)在一般利用這個(gè)特性來(lái)實(shí)現(xiàn)單例模式推捐。因?yàn)轭愒诔跏蓟臅r(shí)候線程是互斥的,可以完美的解決單例創(chuàng)建沖突的問(wèn)題侧啼。
PS2
單例模式是一種常見(jiàn)的模式牛柒,懶漢模式考慮線程安全需要在獲取單例的方法添加synchronized
關(guān)鍵字實(shí)現(xiàn)同步代碼塊,這樣造成了性能損耗痊乾;而餓漢模式不能延遲實(shí)例化對(duì)象皮壁,靜態(tài)內(nèi)部類單例模式的實(shí)現(xiàn),既保證了線程的安全哪审,有能夠延遲加載蛾魄,也就是在第一次使用的時(shí)候加載。