全部
技术
PHP
MySQL
前端
Linux
JAVA
工具
纪念日计算器
邮记星
个人记账
笔记侠
历史上的今天
生日密码
生日书
生日密码
生日花语
博古通今
三十六计
鬼谷子
笑林广记
本草纲目
山海经
唐诗宋词
宋词300首
唐诗300首
退出
登录
注册
编辑文章
选择分类
PHP
MySQL
前端
Linux
Java
工具
选择专栏
设计模式
java基础
Angular学习
Java面试题
描述:
java 锁
封面图上传 :
+
点击上传图片
### java 锁 **1. 公平锁** 指多个线程按照请求锁的顺序来获取锁,类似排队打饭,先来后到。 公平锁就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空或者当前时等待队列的第一个,就占有锁,否则就加入等待队列中,以后会按照FIFO(先进先出)的规则从队列中去到自己 **2.非公平锁** 是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请锁的线程优先获取锁。在高并发的情况下,可能会造成优先级反转或者饥饿现象 非公平锁比较粗鲁,上来先尝试占有锁,如果尝试失败,就再采取类似于公平锁的那种方式。 非公平锁的优点在于**吞吐量比公平锁大** **对于Synchronized而言,也是一种非公平锁** ----- **并发包中的ReentrantLock可以指定构造函数的boolean 类型来得到公平锁或者非公平锁,默认非公平锁** ```java Lock a = new ReentrantLock(true);//公平锁 Lock b = new ReentrantLock(false);//非公平锁 Lock c = new ReentrantLock();//默认非公平锁 ``` --- **3. 可重入锁 (又名递归锁)** 指的时同一个线程外层函数获取锁后,内层递归函数仍然能获取该锁的代码,在同一个线程的外层方法获取锁的时候,在进入内层方法或自动获取锁。也就是说 线程可以进入任何一个它已经拥有锁所同步的代码块。 如下代码,可重入锁的意思就是,当线程获取了method01的锁后,里面再访问加锁的method02时,无需再次获取method02的锁,默认有这个锁,同上来说,你有了进你家大门钥匙,那么你就可以去你家厕所。 ```java public syncronized void method01(){ method02(); } public syncronized void method02(){ } ``` 下面代码执行结果: set 的进程信息:Thread-0 get 的进程信息:Thread-0 set 的进程信息:Thread-1 get 的进程信息:Thread-1 虽然set也加锁了,但是get得到锁后,相当于也得到了set的锁 ```java package com.bowen; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class TestReentantLock implements Runnable{ Lock lock = new ReentrantLock(); @Override public void run() { get(); } public void get(){ lock.lock(); try { set(); System.out.println("get 的进程信息:"+Thread.currentThread().getName()); }finally{ lock.unlock(); } } public void set(){ lock.lock(); try { System.out.println("set 的进程信息:"+Thread.currentThread().getName()); }finally{ lock.unlock(); } } } public class TestLock { public static void main(String[] args) { TestReentantLock a = new TestReentantLock(); Thread t1 = new Thread(a); Thread t2 = new Thread(a); t1.start(); t2.start(); } } ``` **4. 自旋锁(spinlock)** 是指尝试获取锁的线程不会立即阻塞,而是**采取循环的方式去尝试获取锁**。这样好处时减少线程上下文切换的消耗,缺点是会循环消耗CPU . 典型例子:unsafe.getAndAddInt方法 ```JAVA public final int getAndAddInt(Object var1, long var2, int var4){ int var5; do{ var5 = this.getIntVolatile(var1, var2); }while(!this.compareAndSwapInt(var1, var2, var5+var4)); return var5; } ``` --- 手写自旋锁 ```java //自旋锁 class TestSpinLock{ AtomicReference
atomicReference = new AtomicReference<>(); public void myLock(){ Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() +"come in lock~!"); while(!atomicReference.compareAndSet(null, thread)){ } } public void myUnLock(){ Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() +"come in unlock~!"); atomicReference.compareAndSet(thread, null); } } public class TestLock { public static void main(String[] args) { // TestReentantLock a = new TestReentantLock(); // Thread t1 = new Thread(a); // Thread t2 = new Thread(a); // t1.start(); // t2.start(); TestSpinLock testSpinLock = new TestSpinLock(); new Thread(()->{ testSpinLock.myLock(); try { TimeUnit.SECONDS.sleep(5); }catch (InterruptedException e){} testSpinLock.myUnLock(); },"AA").start(); new Thread(()->{ testSpinLock.myLock(); try { TimeUnit.SECONDS.sleep(5); }catch (InterruptedException e){} testSpinLock.myUnLock(); },"BB").start(); } } //结果 AAcome in lock~! BBcome in lock~! AAcome in unlock~! BBcome in unlock~! ``` **5. 独占锁(写锁)** 指该锁一次只能被一个线程持有。对ReentrantLock和ASynchronized 是独占锁 **6. 共享锁(读锁)** 指该锁可被多个线程所持有,对ReentrantReadWriteLock其读锁是共享锁,写锁是独占锁, 读的共享锁可以保证并发读是非常高效的,读写,写读,写写的过程互斥
保存文章