1. ReadWriteLock
示例一:讀寫隊列
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* 讀寫鎖:分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥,這是由JVM自己控制的,我們只需上好相應的鎖即可
*/
public class ReadWriteLockDemo {
public static void main(String[] args){
final MyQueue mq=new MyQueue();
Runnable readR=new Runnable(){
@Override
public void run() {
for(int i=0;i<20;i++){
mq.read();
}
}
};
Thread readThread1=new Thread(readR);
Thread readThread2=new Thread(readR);
Runnable writeR=new Runnable(){
@Override
public void run() {
for(int i=0;i<20;i++){
mq.write();
}
}
};
Thread writeThread1=new Thread(writeR);
Thread writeThread2=new Thread(writeR);
readThread1.start();
readThread2.start();
writeThread1.start();
writeThread2.start();
}
}
class MyQueue{
private String data=null;
private static int count=0;
//讀寫鎖
ReadWriteLock rwl=new ReentrantReadWriteLock();
public void read(){
rwl.readLock().lock();
try{
System.out.println();
System.out.println(Thread.currentThread().getName()+"be ready to read...............................");
try {
Thread.sleep((long) (Math.random()*20));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"read data="+data);
}finally{
rwl.readLock().unlock();
}
}
public void write(){
rwl.writeLock().lock();
System.out.println();
System.out.println(Thread.currentThread().getName()+"be ready to write...............................");
try{
try {
Thread.sleep((long) (Math.random()*20));
} catch (InterruptedException e) {
e.printStackTrace();
}
data="this is data "+count;
count++;
System.out.println(Thread.currentThread().getName()+"........write data: "+data);
}finally{
rwl.writeLock().unlock();
}
}
}
示例二:緩存系統
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheSystem {
private Map<String,Object> mapCache=new HashMap<String,Object>();
private ReadWriteLock rwl=new ReentrantReadWriteLock();
Object getData(String key){
rwl.readLock().lock();
Object value=null;
try{
value=mapCache.get(key);
if(value==null){
//獲取寫鎖之前必須釋放讀鎖
rwl.readLock().unlock();
rwl.writeLock().lock();
try{
if(value==null){
value="aaaaa";//實際開發中是讀數據庫
mapCache.put(key, value);
}
}finally{
//鎖降級:釋放寫鎖之前,獲取讀鎖
rwl.readLock().lock();
rwl.writeLock().unlock();
}
}
//使用數據:返回數據
return value;
}finally{
rwl.readLock().unlock();
}
}
}
2. Condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 假定有一個綁定的緩衝區,它支持 put 和 take 方法。
* 如果試圖在空的緩衝區上執行 take 操作,則在某一個項變得可用之前,線程將一直阻塞;
* 如果試圖在滿的緩衝區上執行 put 操作,則在有空間變得可用之前,線程將一直阻塞。
*/
public class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[10];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
Thread.sleep((long) (Math.random()*100));
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
System.out.println(Thread.currentThread().getName()+" put in position "+putptr+": "+ x);
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
Thread.sleep((long) (Math.random()*100));
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
System.out.println(Thread.currentThread().getName()+" take from position "+takeptr+": "+ x+" ............");
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
public static void main(String[] args){
final BoundedBuffer bb=new BoundedBuffer();
Runnable putR=new Runnable(){
@Override
public void run() {
for(int i=0;i<20;i++){
try {
bb.put("item"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable takeR=new Runnable(){
@Override
public void run() {
for(int i=0;i<20;i++){
try {
bb.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t1=new Thread(putR);
Thread t2=new Thread(putR);
Thread t3=new Thread(takeR);
Thread t4=new Thread(takeR);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
3. Semaphore
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @author zj
* 1. Semaphore可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,
* 例如,實現一個文件允許的併發訪問數。
* 2. 單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另外一個線程釋放“鎖”,
* 這可應用於死鎖恢復的一些場合。
* 將信號量初始化爲 1,使得它在使用時最多隻有一個可用的許可,從而可用作一個相互排斥的鎖。這通常也稱爲二進制信號量,
* 因爲它只能有兩種狀態:一個可用的許可,或零個可用的許可。按此方式使用時,二進制信號量具有某種屬性(與很多 Lock 實現不同),
* 即可以由線程釋放“鎖”,而不是由所有者(因爲信號量沒有所有權的概念)。在某些專門的上下文(如死鎖恢復)中這會很有用。
*/
public class SemaphoreDemo {
public static void main(String[] args){
ExecutorService threadPool=Executors.newCachedThreadPool();
final Semaphore sp=new Semaphore(3);
for(int i=0;i<10;i++){
Runnable r=new Runnable(){
@Override
public void run() {
try {
sp.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("線程"+Thread.currentThread().getName()+"已進入,當前已有"+(3-sp.availablePermits())+"個線程併發");
try {
Thread.sleep((long) (Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
sp.release();
System.out.println("線程"+Thread.currentThread().getName()+"已經離開........當前還有"+(3-sp.availablePermits())+"個線程併發");
}
};
threadPool.execute(r);
}
threadPool.shutdown();
}
}