優化思路:避免死鎖、減少鎖粒度、鎖分離等
一、線程開銷
1.處理線程任務外,還要維護多線程環境的特有信息,如:線程本身的元數據,線程的調度,線程上下文的切換等,更多的在于多線程的調度。
二、避免死鎖
死鎖是多線程特有的問題,在死鎖時,線程間互相等待資源,而又不釋放鎖定的資源,導致一直等待。
一般需要滿足以上條件:
1.互斥條件:一個資源只能有一個進程使用
2.請求與保持條件:對已獲得的資源不釋放
3.不剝奪條件:進程已獲得資源,在進程執行完之前,不能強行剝奪
4.循環等待條件:若干線程形成一種頭尾相接的循環等待資源
就像形成頭尾相連的四個小車一樣
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的順序執行代碼");
}
}
}
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順序執行代碼");
}
}
}
}
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,接著去請求lock2;線程2獲得lock2,接著請求lock1。由于線程2持有lock2不能釋放,而線程1去請求lock2無法獲得則一直等待;而線程1持有lock1,線程2去請求lock1無法獲得則一直等待,這樣導致兩個線程一直等待爭搶資源,循環等待
死鎖檢測:
1.使用Jconsole,檢測線程死鎖,可以看到死鎖代碼行
2.使用線程dump,可以打印輸出locked,查找到死鎖情況
破死鎖,可以破壞導致死鎖的四個條件的任何一個。
三、減少鎖的持有時間
鎖的作用范圍越小越精確,比如:
synchronized (lock1) {
try {
othercode1();
synchronized method();
othercode2();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
假設othercode1和othercode2 耗時較長 ,且無需同步,則需要將synchronized加在 需要同步的代碼塊上。
四、減少鎖的粒度
在ConcurrentMap類使用分段鎖,將整個大對象拆分成多個segments,然后對每個segment加鎖,從而實現高并發,減少整體鎖的時間。
五、使用讀寫鎖代替獨占鎖
讀寫鎖利用了讀寫鎖分類的思想,從而針對讀多寫少的情況進行性能的優化
六、原子操作
原子操作如 AtomicInteger等采用CAS思想設計,CompareAndSet,是一種無鎖的實現