理論知識很枯燥,但這些都是基本功,學完可能會忘,但等用的時候,會發覺之前的學習是非常有意義的,學習線程就是這樣子的.
1.如何創建鎖?
Lock lock = new ReentrantLock();
2.如何使用鎖?
可以參看Lock文檔,其使用格式如下:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
在要用的方法前加上鎖,比如寫操作,然后在finally中將鎖打開.
這里,將前文java核心知識點學習----多線程並發之線程同步中的代碼改用Lock實現數據同步,改寫代碼如下:
package com.amos.concurrent;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @ClassName: LockTest
* @Description: Lock學習
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 22, 2014 1:48:36 AM
*/
public class LockTest {
public static void main(String[] args) {
new LockTest().init();
}
private void init() {
final OutPuter outPuter = new OutPuter();
// 新建一個線程
new Thread(new Runnable() {
public void run() {
while (true) {
// 休息10ms
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPuter.output("hi_amos");// 輸出
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPuter.output("amosli");
}
}
}).start();
}
static class OutPuter {
// 方式1:使用synchronized關鍵字
// public synchronized void output(String name) {
// int length = name.length();
// for (int i = 0; i < length; i++) {
// System.out.print(name.charAt(i));
// }
// System.out.println();
// }
// 方式2:使用Lock鎖
Lock lock = new ReentrantLock();
public void output(String name) {
lock.lock();// 加鎖
int length = name.length();
// 輸出name,逐個字節讀取,並輸出
try {
for (int i = 0; i < length; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
} finally {
lock.unlock();// 解鎖
}
}
}
}
3.synchronized關鍵字與Lock的區別?
1).Lock是Java5中的新特性,更加面向對象.更類似於生活中的鎖.
2).Lock鎖一般需要手動開啟和關閉,而synchronized則不需要.
建議優先使用Lock.
4.注意事項:
1)多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥.
2)要實現兩個線程互斥,那么要將鎖加到同一個被訪問對象上.
3)如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖,總之,讀的時候用讀鎖,寫的時候用寫鎖!
5.設計一個緩存系統
什么是緩存系統? 就是看本地是否已經緩存過此數據,如果已經緩存過,那就直接拿來用;如果沒有緩存過,那就查詢數據庫.
下面看代碼:
private Map<String, Object> cache = new HashMap<String, Object>();
public synchronized Object getData(String key){
Object object = cache.get(key);
if (object==null) {
object = "1323";//實際是去queryDB();
}
return object;
}
這里其實是一個超級簡單的緩存系統,原理就是:第一次訪問的時候把值存入到cache中,第二次訪問時,先去看cache中是否有值如果有值,那么就直接去取值,而不是從數據庫中去取.
為什么要加上synchronized? 這是為了保持數據互斥,訪問的時候不相互影響,因為其中有對object進行賦值操作,這是一個寫操作,所以最好加上鎖.
如何優化?
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public synchronized Object getData(String key){
rwl.readLock();//read lock
Object object = cache.get(key);
try{
if (object==null) {
rwl.readLock().unlock();//釋放鎖
rwl.writeLock().lock();//對寫加鎖
try{
object = "1323";//實際是去queryDB();
}finally{
rwl.writeLock().unlock();
}
}
}finally{
rwl.readLock().unlock();
}
return object;
}
上面的代碼運用到了剛學到的知識,對所有讀和寫進行加鎖,以保持線程間的互斥,要特別注意的是要在finally中把鎖打開,不管程序是否執行成功,因為如果不解鎖,那么程序將會產生死鎖,關於死鎖,將在接下來的文章中介紹.

