Java基础:多线程之ReadWriteLock、Condition、Semaphore

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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值