• Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统


    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 

    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中把锁打开,不管程序是否执行成功,因为如果不解锁,那么程序将会产生死锁,关于死锁,将在接下来的文章中介绍.

  • 相关阅读:
    poj 2560Freckles (krusual)
    ACRush 楼天成回忆录
    大腕版ACMICPC比赛
    POJ刷题
    DataGrid中添加DropdownList时的数据绑定
    【转帖】SQL Server各种日期计算方法(收藏)
    安全配置Win2000服务器
    C#写的一个代码生成器
    .Net 常用加密算法类
    实习之最
  • 原文地址:https://www.cnblogs.com/ncy1/p/9164474.html
Copyright © 2020-2023  润新知