来源:互联网 发布:java实体是什么 编辑:程序博客网 时间:2024/04/29 15:15

一,基本概念

节约篇幅,锁(Lock)是什么就不说了,先列出几个重要的概念。

锁级别:分为对象级和类级,常见的大部分锁是对象锁;所有(或者绝大部分)的类和对象都自带一把隐藏的锁,这也是synchronized能锁任意对象和类的根本所在。每个对象有自己的对象锁,所有对象共用一个类锁。

可重入性:假设条件:锁住的方法中调用另一个锁住的方法,且两个锁是同一个对象。结果:如果该锁具有可重入性,则自动识别放行,常见的大部分锁都是这种类型;如果该锁不具备可重入性,则产生死锁。

互斥和非互斥:互斥就是同一时刻只能有一个线程访问,常见的大部分锁都是这种类型;非互斥就是(!互斥),比如读写锁(ReadWriteLock)能支持多个线程同时读,就不是互斥锁。

公平和非公平:公平就是遵循先到先得(FIFO)的原则,非公平则竞争获取,看cpu的心情。


二,体系结构


需要注意的是,LockReadWriteLock是两个不同的接口,对应两个不种不同的体系结构。ReadWriteLockJDK实现类ReentrantReadWriteLock内置一个ReadLock和一个WriteLock。非重入性的锁我从JDK1.7以及网络都没找到,以后遇到再补充,也希望高手补充下。


三,常见实例

关于synchronized

Lock其实是一个独立的概念,但是在简单的应用中我们常常使用synchronized关键字来解决对象多线程同步访问的问题。synchronized可以锁整个方法,也可以锁某个小范围的过程。

public class SynTest{// 对象级别锁,锁住当前对象,也就是thispublic synchronized void syn1(){// do something}// 类级别锁,锁住当前对象的类,也就是SynTest.classpublic synchronized static void syn2(){// do something}// 对象级别锁,锁住当前对象,也就是thispublic void syn3(){synchronized(this){// do something}}// 对象级别锁,锁住list实例public void syn4(){List<String> list = new ArrayList<String>();synchronized(list){// do something}}// 类级别锁,锁住SynTest.class,跟syn2()一样public void syn5(){synchronized(SynTest.class){// do something}}// 对象级别锁,锁住当前对象,也就是thispublic synchronized void syn6(){// 线程运行到这里的时候,this对象把锁交给该线程,syn1要求获取this锁才行运营,this锁具有可重入性,所以syn1也可以执行syn1();}}

synchronized其实是一种隐式的上锁,本质上也是对Lock的操作,只需要理解到底是哪个对象被锁住了即可。

自定义锁:

synchronized提供了一种便捷的上锁方式,我们有时候还会自定义锁对象,因为自定义锁对象的一些高级特性是synchronized无法拥有的,而且应用更灵活。这里主要介绍ReentrantLockReentrantReadWriteLock

ReentrantLock:

结合我遇到的实际情况来说明吧,我们有一个场景是对线路做监控,如果线路调度连续失败的次数超过一定的阀值(基本都是该线路失联了),则智能切换到其他线路。代码结构如下,可以看到tryLock方法不阻塞其他线程的特性。

public class Watcher{private static final int ERROR_THRESHOLD = 100;private static Integer failCount = 0;private static ReentrantLock lock = new ReentrantLock();// 失败次数递增public static void add(){synchronized(failCount){failCount++;}if(failCount > ERROR_THRESHOLD)// 连续失败次数大于切换阀值{lock.tryLock();try{// 只能有一个线程执行切换,切换代码省略}catch(Exception e){e.printStackTrace();}finally{lock.unlock();}}}// 失败次数重置public static void reset(){synchronized(failCount){failCount = 0;}}}

ReentrantReadWriteLock:

这个是一个非互斥锁,特性是只能有一个线程可以写,写的时候不能读,读的时候不能写,读的时候还能读。看到这个特性,就知道它是为操作一些需要常常读取,但是很少需要修改的数据而定制的。从我实际遇到的情况来说,就是关键字过滤功能,关键字库一般初始化好放内存中,只在很少的情况下需要去修改这个内存。

public class KeywordService{private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 关键字匹配public static void matchKeyword(String msg){lock.readLock().lock();try{// 执行匹配}catch(Exception e){e.printStackTrace();}finally{lock.readLock().unlock();}}// 重置关键字到内存public static void reloadKeyword(){lock.writeLock().lock();try{// 重载关键字到内存}catch(Exception e){e.printStackTrace();}finally{lock.writeLock().unlock();}}}






0 0
原创粉丝点击