2019独角兽企业重金招聘Python工程师标准>>>

两种互斥锁机制:

1、synchronized

2、ReentrantLock

ReentrantLock是jdk5的新特性,采用ReentrantLock可以完全替代替换synchronized传统的锁机制,而且采用ReentrantLock的方式更加面向对象,也更加灵活,网上有很多关于对比两者锁方式的文章,这里就不多口舌了,大家baidu、google一下就水落石出了。在本博客中也写关于这两种锁方式实现的经典例子《生产者消费者》。

synchronized方式:《java线程:三种方式实现生产者消费者问题_1》

ReentranLock方式:《java线程:三种方式实现生产者消费者问题_2》

关于读写锁,用语言解释不如直接用代码诠释,以下通过两个例子讲述读写锁以及读写锁的使用:

例子1:

import java.util.HashMap;  
import java.util.Map;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
/** 
 * @author amber2012 
 *  
 * 读写锁:ReadWriteLock 
 *  
 * 在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题。比如在一个线程读取数据的时候,另外一个线程在 
 * 写数据,而导致前后数据的不一致性;一个线程在写数据的时候,另一个线程也在写,同样也会导致线程前后看到的数据的 
 * 不一致性。 
 *  
 * 这时候可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这 
 * 样是可以解决这样以上的问题,但是效率却大打折扣了。因为在真实的业务场景中,一份数据,读取数据的操作次数通常高 
 * 于写入数据的操作,而线程与线程间的读读操作是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期 
 * 间上锁就行了。 
 *  
 * 对于这种情况,读写锁则最好的解决方案! 
 *  
 * 读写锁的机制: 
 *      "读-读"不互斥 
 *      "读-写"互斥 
 *      "写-写"互斥 
 *  
 * 即在任何时候必须保证: 
 *      只有一个线程在写入; 
 *      线程正在读取的时候,写入操作等待; 
 *      线程正在写入的时候,其他线程的写入操作和读取操作都要等待; 
 *  
 * 以下是一个缓存类:用于演示读写锁的操作:重入、降级 
 */  
public class CachedData {  
    // 缓存都应该是单例的,在这里用单例模式设计:  
    private static CachedData cachedData = new CachedData();  
    private final ReadWriteLock lock = new ReentrantReadWriteLock();//读写锁  
    private Map<String, Object> cache = new HashMap<String, Object>();//缓存  
      
    private CachedData(){  
    }  
      
    public static CachedData getInstance(){  
        return cachedData;  
    }  
      
    // 读取缓存:  
    public Object read(String key) {  
        lock.readLock().lock();  
        Object obj = null;  
        try {  
            obj = cache.get(key);  
            if (obj == null) {  
                lock.readLock().unlock();  
                // 在这里的时候,其他的线程有可能获取到锁  
                lock.writeLock().lock();  
                try {

obj = cache.get(key); //这个是必要的!!!!
                    if (obj == null) {  
                        obj = "查找数据库"; // 实际动作是查找数据库  
                        // 把数据更新到缓存中:  
                        cache.put(key, obj);  
                    }  
                } finally {  
                    // 当前线程在获取到写锁的过程中,可以获取到读锁,这叫锁的重入,然后导致了写锁的降级,称为降级锁。  
                    // 利用重入可以将写锁降级,但只能在当前线程保持的所有写入锁都已经释放后,才允许重入 reader使用  
                    // 它们。所以在重入的过程中,其他的线程不会有获取到锁的机会(这样做的好处)。试想,先释放写锁,在  
                    // 上读锁,这样做有什么弊端?--如果这样做,那么在释放写锁后,在得到读锁前,有可能被其他线程打断。  
                    // 重入————>降级锁的步骤:先获取写入锁,然后获取读取锁,最后释放写入锁(重点)  
                    lock.readLock().lock();   
                    lock.writeLock().unlock();  
                }  
            }  
        } finally {  
            lock.readLock().unlock();  
        }  
        return obj;  
    }  
}

例子2:

import java.util.Map;  
import java.util.TreeMap;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
import javax.xml.crypto.Data;  
  
/** 
 * @author amber2012 
 *  
 * jdk文档中关于ReentrantReadWriteLock类使用的一个很好的例子,以下是具体的介绍: 
 *  
 * 在使用某些种类的 Collection 时,可以使用 ReentrantReadWriteLock 来提高并发性。通常,在预期 collection 
 * 很大,读取者线程访问它的次数多于写入者线程,并且 entail 操作的开销高于同步开销时,这很值得一试。例如,以下 
 * 是一个使用 TreeMap 的类,预期它很大,并且能被同时访问。  
 */  
public class RWDictionary {  
  
    private final Map<String, Data> map = new TreeMap<String, Data>();  
    private final ReadWriteLock rwl = new ReentrantReadWriteLock();  
    private final Lock readLock = rwl.readLock();  
    private final Lock writeLock = rwl.writeLock();  
  
    public Data get(String key) {  
        readLock.lock();  
        try {  
            return map.get(key);  
        } finally {  
            readLock.unlock();  
        }  
    }  
  
    public String[] allKeys() {  
        readLock.lock();  
        try {  
            return (String[]) map.keySet().toArray();  
        } finally {  
            readLock.unlock();  
        }  
    }  
  
    public Data put(String key, Data value) {  
        writeLock.lock();  
        try {  
            return map.put(key, value);  
        } finally {  
            writeLock.unlock();  
        }  
    }  
  
    public void clear() {  
        writeLock.lock();  
        try {  
            map.clear();  
        } finally {  
            writeLock.unlock();  
        }  
    }  
}

转载于:https://my.oschina.net/v512345/blog/741472

java线程:互斥锁与读写锁相关推荐

  1. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

  2. golang:1.并发编程之互斥锁、读写锁详解

    本文转载自junjie,而后稍作修改. 一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是 ...

  3. PHP程序中的文件锁、互斥锁、读写锁使用技巧解析

    文件锁全名叫 advisory file lock, 书中有提及. 这类锁比较常见,例如 mysql, php-fpm 启动之后都会有一个pid文件记录了进程id,这个文件就是文件锁. 这个锁可以防止 ...

  4. 同步方法中的锁对象_互斥锁与读写锁:如何使用锁完成Go程同步?

    图转自https://colobu.com/2018/12/18/dive-into-sync-mutex/ 这张图容易让人产生误解,容易让人误以为goroutine1获取的锁,只有goroutine ...

  5. 互斥锁机制,互斥锁与读写锁区别

    Linux的4种锁机制: 互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象.当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒 读写锁:rwlock,分为读锁和写锁.处于读操作时 ...

  6. DCMTK:定义信号灯,互斥锁和读/写锁的类

    DCMTK:定义信号灯,互斥锁和读/写锁的类 定义信号灯,互斥锁和读/写锁的类 定义信号灯,互斥锁和读/写锁的类 #include "dcmtk/config/osconfig.h" ...

  7. 嵌入式 自旋锁、互斥锁、读写锁、递归锁

    互斥锁(mutexlock): 最常使用于线程同步的锁:标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁:临界区和互斥量都可用来实现此锁,通常情况下锁操作失败会将该线程 ...

  8. 并发编程中常见的锁机制:乐观锁、悲观锁、CAS、自旋锁、互斥锁、读写锁

    文章目录 乐观锁 VS 悲观锁 悲观锁 乐观锁 CAS CAS机制 ABA问题 CAS的优缺点 互斥锁 VS 自旋锁 互斥锁 自旋锁 对比及应用场景 读写锁 实现方式 读写锁 VS 互斥锁 乐观锁 V ...

  9. 第十二节:深究内核模式锁的使用场景(自动事件锁、手动事件锁、信号量、互斥锁、读写锁、动态锁)

    一. 整体介绍 温馨提示:内核模式锁,在不到万不得已的情况下,不要使用它,因为代价太大了,有很多种替代方案. 内核模式锁包括: ①:事件锁 ②:信号量 ③:互斥锁 ④:读写锁 ⑤:动态锁 二. 事件锁 ...

最新文章

  1. html中Marquee属性详解
  2. flex 正则表达式匹配规则
  3. MySQL的常见命令
  4. OpenCV-数字图像处理之中值滤波
  5. asp.net后台管理系统-登陆模块-路由权限控制_1
  6. jQuery的hide() 、show() 、toggle()
  7. 私藏的开发过程中的那些基类
  8. ORACLE RMAN备份及还原
  9. sql server 远程连接问题
  10. FISCO BCOS java sdk 组装交易的代码位置
  11. IPMI IPMB协议
  12. 流量转发的思路-软件流量转发 管家婆 客户端 端口 更改
  13. pip更新不成功/Python虚拟环境下如何更新pip(Pycharm)
  14. 如何在CAD图纸中添加文字
  15. SecKill——一款超级好用的抢单软件
  16. linux清理垃圾文件,linux如何清理系统垃圾
  17. 计算图片中矩形间的IOU
  18. 游戏服务器会遭到什么攻击,被攻击了怎么防御
  19. 二进制文件转文本工具
  20. cf596B. Wilbur and Array

热门文章

  1. Android中的设计模式-状态模式
  2. 第二篇: Mysql____语法格式——键值
  3. Photoshop CS6软件安装教程
  4. java filestream 包,java.io.FileOutputStream.write(byte[] b)
  5. 自动化监控--添加itme的web页面详解
  6. mysql多实例安装配置演示
  7. windows一键安装web环境全攻略(win2008)
  8. Windows下Memcache的安装及PHP扩展配置方法
  9. win2003服务器的一些安全设置
  10. win2003 ip安全策略