在上一節中,我們已經瞭解了Java多線程編程中常用的關鍵字synchronized,以及與之相關的對象鎖機制。這一節中,讓我們一起來認 識JDK 5中新引入的並發架構中的鎖機制。
我想很多購買了《Java程式員面試寶典》之類圖書的朋友一定對下面這個面試題感到非常熟悉:
問:請對比synchronized與java.util.concurrent.locks.Lock 的異同。
答案:主要相同點:Lock能完成synchronized所實現的所有功能
主要不同點:Lock有比synchronized更精確的線程語義和更好的效能。synchronized會自動釋放鎖,而Lock一定要求程式員手工釋放, 並且必須在finally從句中釋放。
恩,讓我們先鄙視一下應試教育。
言歸正傳,我們先來看一個多線程程式。它使用多個線程對一個Student對象進行訪問,改變其中的變數值。我們首先用傳統的 synchronized 機制來實現它:
public class ThreadDemo implements Runnable {
class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student student = new Student();
int count = 0;
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td, "a");
Thread t2 = new Thread(td, "b");
Thread t3 = new Thread(td, "c");
t1.start();
t2.start();
t3.start();
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
synchronized (this) {//(1)使用同一個ThreadDemo對象作為同步鎖
System.out.println(currentThreadName + " got lock1@Step1!");
try {
count++;
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count:" + count);
}
}
System.out.println(currentThreadName + " release lock1@Step1!");
synchronized (this) {//(2)使用同一個ThreadDemo對象作為同步鎖
System.out.println(currentThreadName + " got lock2@Step2!");
try {
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
this.student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + this.student.getAge());
Thread.sleep(5000);
} catch (Exception ex) {
ex.printStackTrace();
} finally{
System.out.println("thread " + currentThreadName + " second read age is:" + this.student.getAge());
}
}
System.out.println(currentThreadName + " release lock2@Step2!");
}
}