追其同步的根本的目的,是控制競爭資源的正確的訪問,因此只要在訪問競爭資源的時候保證同一時刻只能一個線程訪問即可,因此Java引入了同步代碼快的策略,以提高性能。
在上個例子的基礎上,對oper方法做了改動,由同步方法改為同步代碼塊模式,程序的執行邏輯並沒有問題。
/**
* Java線程:線程的同步-同步代碼塊
*
* @author leizhimin
*/
public class Test {
public static void main(String[] args) {
User u = new User("張三", 100);
MyThread t1 = new MyThread("線程A", u, 20);
MyThread t2 = new MyThread("線程B", u, -60);
MyThread t3 = new MyThread("線程C", u, -80);
MyThread t4 = new MyThread("線程D", u, -30);
MyThread t5 = new MyThread("線程E", u, 32);
MyThread t6 = new MyThread("線程F", u, 21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyThread extends Thread {
private User u;
private int y = 0;
MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}
public void run() {
u.oper(y);
}
}
class User {
private String code;
private int cash;
User(String code, int cash) {
this.code = code;
this.cash = cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 業務方法
*
* @param x 添加x萬元
*/
public void oper(int x) {
try {
Thread.sleep(10L);
synchronized (this) {
this.cash += x;
System.out.println(Thread.currentThread().getName() + "運行結束,增加“" + x + "”,當前用戶賬戶余額為:" + cash);
}
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "User{" +
"code='" + code + '\'' +
", cash=" + cash +
'}';
}
}
線程E運行結束,增加“32”,當前用戶賬戶余額為:132
線程B運行結束,增加“-60”,當前用戶賬戶余額為:72
線程D運行結束,增加“-30”,當前用戶賬戶余額為:42
線程F運行結束,增加“21”,當前用戶賬戶余額為:63
線程C運行結束,增加“-80”,當前用戶賬戶余額為:-17
線程A運行結束,增加“20”,當前用戶賬戶余額為:3
Process finished with exit code 0
注意:
在使用synchronized關鍵字時候,應該盡可能避免在synchronized方法或synchronized塊中使用sleep或者 yield方法,因為synchronized程序塊占有著對象鎖,你休息那麼其他的線程只能一邊等著你醒來執行完了才能執行。不但嚴重影響效率,也不合邏輯。
同樣,在同步程序塊內調用yeild方法讓出CPU資源也沒有意義,因為你占用著鎖,其他互斥線程還是無法訪問同步程序塊。當然與同步程序塊無關的線程可以獲得更多的執行時間。
出處:http://lavasoft.blog.51cto.com/62575/221922