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();
}
}