java并发包中的lock

一:java并发包

jdk 1.5引入了java.util.concurrent并发包,里面提供了各种强大的并发工具,让并发编程变得更容易。本文简单介绍一下并发包提供的锁(lock)。


二:锁的使用

使用并发包的锁时,通常代码结构如下:

     Lock l = ...;
     l.lock();
     try {
         // 操作共享资源
     } finally {
         l.unlock();
     }


在finally里释放锁,确保锁能释放。


(1)ReentrantLock。ReentrantLock作用就像synchronized关键字。

下面是使用ReentrantLock的示例

public class ReentrantLockTest {

    private static class NamePrinter {

        private Lock lock = new ReentrantLock();

        public void print(String name) {

            try {
                
                lock.lock();

                //将名字逐个字母输出
                for (int i = 0; i < name.length(); i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();

            } finally {
                //确保最后能释放锁
                lock.unlock();
            }

        }

    }

    public static void main(String[] args) {

        final NamePrinter namePrinter = new NamePrinter();

        while (true) {

            new Thread(new Runnable() {
                @Override
                public void run() {
                    namePrinter.print("liudehua");
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    namePrinter.print("zhangxueyou");
                }
            }).start();

        }

    }

}


(2)ReentrantReadWriteLock。读写锁,多个线程之间可以同时读数据,但如果一个线程在写数据,其他线程不能写数据也不能读数据。

ReentrantReadWriteLock 示例1:模拟一个队列,多个线程之间可以同时读数据,但如果一个线程在写数据,其他线程不能写数据也不能读数据

public class MockQueueTest {

    public static void main(String[] args) {

        final MockQueue queue = new MockQueue();

        while (true) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    queue.write();
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    queue.read();
                }
            }).start();
        }

    }

    /**
     * 模拟一个队列。
     */
    private static class MockQueue {

        private int data = -1;

        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        private final Lock rl = readWriteLock.readLock();
        private final Lock wl = readWriteLock.writeLock();

        public void read() {

            rl.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " is ready to read data...");
                TimeUnit.SECONDS.sleep((long) (Math.random() * 3));
                System.out.println(Thread.currentThread().getName() + " reads the data:" + data);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                rl.unlock();
            }
        }

        public void write() {

            wl.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " is ready to write data...");
                int temp = (int) (Math.random() * 10000);
                this.data = temp;
                TimeUnit.SECONDS.sleep((long) (Math.random() * 3));
                System.out.println(Thread.currentThread().getName() + " writes the data:" + temp);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                wl.unlock();
            }
        }

    }

}


ReentrantReadWriteLock 示例2:模拟一个简单的缓存

public class SimpleCacheTest {

    public static void main(String[] args) {
        final SimpleCache simpleCache = new SimpleCache();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Integer value1 = simpleCache.get("key1");
                System.out.println("value1=" + value1);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Integer value2 = simpleCache.get("key1");
                System.out.println("value2=" + value2);
            }
        }).start();

    }

    private static class SimpleCache {

        private Map<String, Integer> cacheMap = new HashMap<String, Integer>();

        private final Random random = new Random();
        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        private final Lock rl = readWriteLock.readLock();
        private final Lock wl = readWriteLock.writeLock();

        public Integer get(String key) {

            rl.lock();
            Integer value = null;

            try {

                value = cacheMap.get(key);
                if (value == null) {
                    rl.unlock();
                    //A
                    wl.lock();
                    try {

                        value = cacheMap.get(key);

                        if (value == null) {  //这里需要再次判断,因为在A处可能有多个线程在等待
                            value = random.nextInt(1000);
                            TimeUnit.SECONDS.sleep(random.nextInt(3));

                            System.out.println("put data into cache...");
                            cacheMap.put(key, value);
                        } else {
                            System.out.print("get data from cache....");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        wl.unlock();
                    }
                    rl.lock();//释放写锁后再加上读锁
                } else {
                    System.out.print("get data from cache....");
                }

            } finally {
                rl.unlock();
            }

            return value;

        }

    }

}


三:线程通信

生成lock对象后,可以调用newCondition方法获得Condition对象,从而调用Condition对象的await、signal/signalAll方法来实现线程通信。await的作用就像wait方法,而signal/signalAll的作用就像notify/notifyAll方法。注意:一个lock对象可以绑定多个Condition对象。


示例1:计算1到100的和。一个线程负责计算,另一个线程负责获取计算结果。

public class CalculatorTest {

    private static class Calculator {

        private boolean shouldCalculate = true;//是否是计算
        private int result;//计算结果

        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();

        /**
         * 计算
         */
        public void calculate() {
            lock.lock();
            while (!shouldCalculate) { //如果不是计算,则等待
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                for (int i = 1; i <= 100; i++) {
                    result += i;
                }

                shouldCalculate = false;
                condition.signal();
            } finally {
                lock.unlock();
            }

        }

        /**
         * 返回计算结果
         */
        public int getResult() {

            lock.lock();

            try {
                while (shouldCalculate) {  //如果是计算,则等待
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                shouldCalculate = true;
                condition.signal();
                return result;

            } finally {
                lock.unlock();
            }

        }

    }

    public static void main(String[] args) {
        final Calculator calculator = new Calculator();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("the result is:" + calculator.getResult());
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                calculator.calculate();
            }
        }).start();

    }
    
}



示例2:实现一个阻塞队列 。如果队列满了则不能放入元素,直到有空间;空了不能取元素,直到有元素入队。注:下面代码来自jdk示例

public class ArrayBlockingQueue {
        private final Lock lock = new ReentrantLock();
        private final Condition notFull = lock.newCondition();
        private final Condition notEmpty = lock.newCondition();

        private final Object[] items = new Object[100];
        private int putptr, takeptr, count;

        /**
         * 入队
         */
        public void put(Object x) throws InterruptedException {
            lock.lock();
            try {
                while (count == items.length) { //满了,等待
                    notFull.await();
                }

                items[putptr] = x;
                if (++putptr == items.length) putptr = 0;
                ++count;
                notEmpty.signal();
            } finally {
                lock.unlock();
            }
        }

        /**
         * 出队
         */
        public Object take() throws InterruptedException {
            lock.lock();
            try {
                while (count == 0) { //空了,等待
                    notEmpty.await();
                }

                Object x = items[takeptr];
                if (++takeptr == items.length) takeptr = 0;
                --count;
                notFull.signal();
                return x;
            } finally {
                lock.unlock();
            }
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值