優(yōu)化思路:避免死鎖召娜、減少鎖粒度、鎖分離等
一惊楼、線程開(kāi)銷(xiāo)
1.處理線程任務(wù)外玖瘸,還要維護(hù)多線程環(huán)境的特有信息,如:線程本身的元數(shù)據(jù)檀咙,線程的調(diào)度雅倒,線程上下文的切換等,更多的在于多線程的調(diào)度弧可。
二蔑匣、避免死鎖
死鎖是多線程特有的問(wèn)題,在死鎖時(shí)棕诵,線程間互相等待資源裁良,而又不釋放鎖定的資源,導(dǎo)致一直等待校套。
一般需要滿足以上條件:
1.互斥條件:一個(gè)資源只能有一個(gè)進(jìn)程使用
2.請(qǐng)求與保持條件:對(duì)已獲得的資源不釋放
3.不剝奪條件:進(jìn)程已獲得資源价脾,在進(jìn)程執(zhí)行完之前,不能強(qiáng)行剝奪
4.循環(huán)等待條件:若干線程形成一種頭尾相接的循環(huán)等待資源
就像形成頭尾相連的四個(gè)小車(chē)一樣
package mythreadpool;
public class DeadThread implements Runnable {
public String username;
public Object lock1 = new Object();
public Object lock2 = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
if (username.equals("a")) {
synchronized (lock1) {
try {
System.out.println("username = " + username);
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("按lock1->lock2的順序執(zhí)行代碼");
}
}
}
if (username.equals("b")) {
synchronized (lock2) {
try {
System.out.println("username = " + username);
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("按lock2->lock1順序執(zhí)行代碼");
}
}
}
}
public void setFlag(String username) {
this.username = username;
}
public static void main(String[] args) {
DeadThread dt1 = new DeadThread();
dt1.setFlag("a");
Thread t1 = new Thread(dt1);
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dt1.setFlag("b");
Thread t2 = new Thread(dt1);
t2.start();
}
}
以上線程1獲得了lock1,接著去請(qǐng)求lock2笛匙;線程2獲得lock2,接著請(qǐng)求lock1侨把。由于線程2持有l(wèi)ock2不能釋放,而線程1去請(qǐng)求lock2無(wú)法獲得則一直等待妹孙;而線程1持有l(wèi)ock1秋柄,線程2去請(qǐng)求lock1無(wú)法獲得則一直等待,這樣導(dǎo)致兩個(gè)線程一直等待爭(zhēng)搶資源蠢正,循環(huán)等待
死鎖檢測(cè):
1.使用Jconsole骇笔,檢測(cè)線程死鎖,可以看到死鎖代碼行
2.使用線程dump,可以打印輸出locked,查找到死鎖情況
破死鎖笨触,可以破壞導(dǎo)致死鎖的四個(gè)條件的任何一個(gè)懦傍。
三、減少鎖的持有時(shí)間
鎖的作用范圍越小越精確旭旭,比如:
synchronized (lock1) {
try {
othercode1();
synchronized method();
othercode2();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
假設(shè)othercode1和othercode2 耗時(shí)較長(zhǎng) ,且無(wú)需同步葱跋,則需要將synchronized加在 需要同步的代碼塊上持寄。
四、減少鎖的粒度
在ConcurrentMap類(lèi)使用分段鎖娱俺,將整個(gè)大對(duì)象拆分成多個(gè)segments稍味,然后對(duì)每個(gè)segment加鎖,從而實(shí)現(xiàn)高并發(fā)荠卷,減少整體鎖的時(shí)間模庐。
五、使用讀寫(xiě)鎖代替獨(dú)占鎖
讀寫(xiě)鎖利用了讀寫(xiě)鎖分類(lèi)的思想油宜,從而針對(duì)讀多寫(xiě)少的情況進(jìn)行性能的優(yōu)化
六掂碱、原子操作
原子操作如 AtomicInteger等采用CAS思想設(shè)計(jì),CompareAndSet慎冤,是一種無(wú)鎖的實(shí)現(xiàn)