立刻有
全部
技术
PHP
MySQL
前端
Linux
JAVA
退出
编辑文章
选择分类
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其读锁是共享锁,写锁是独占锁, 读的共享锁可以保证并发读是非常高效的,读写,写读,写写的过程互斥
保存文章