公平锁和非公平锁

1.公平锁,是指多个线程按照申请的顺序来获取锁,类似排队打饭,先来后到。

2.非公平锁,是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程

比先申请的线程优先获取锁,在高并发情况下,有可能会造成优先级反转或者饥饿现象。

Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁,非公平锁的优点在于吞吐量比公平锁大。

对于Synchronized而言,也是一种非公平锁。


可重入锁(也叫做递归锁)

指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程

在外层方法获取锁的时候,在进入内层方法会自动获取锁。也即是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块。

ReentrantLock/Synchronized就是一个典型的可重入锁,可重入锁的最大作用是避免死锁。

例子:

class Photo implements Runnable{

    public synchronized void sendSMS() throws Exception {
System.out.println(Thread.currentThread().getName()+"\t invoked sendSMS()");
sendEmail();
} public synchronized void sendEmail() throws Exception {
System.out.println(Thread.currentThread().getName()+"\t invoked sendEmail()");
} @Override
public void run() {
get();
}
Lock lock = new ReentrantLock(); public void get() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t invoked sendSMS()");
set();
} finally {
lock.unlock();
}
} public void set() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t invoked sendEmail()");
} finally {
lock.unlock();
}
} } public class ReentrantLockDemo { public static void main(String[] args) {
Photo photo = new Photo();
new Thread(() ->{
try {
photo.sendSMS();
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start(); new Thread(() ->{
try {
photo.sendSMS();
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------------");
Thread t3 = new Thread(photo,"t3");
Thread t4 = new Thread(photo,"t4");
t3.start();
t4.start();
}
} 运行结果见下图


自旋锁(spinlock)

是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU

//unsafe.getAndAddInt(Object var1, long var2,int var4) {

  int var 5;

  do {

    var5  = this.getIntVolatile(var1,var2);

  } while(!this.compareAndSwapInt(var1,var2,var5,var5 + var4))

    return var5;

}

例子:

public class SpinLockDemo {
//原子引用线程
AtomicReference<Thread> atomicReference = new AtomicReference<>(); public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"\t come in");
while (!atomicReference.compareAndSet(null,thread)){ }
} public void myUnlock() {
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
System.out.println(Thread.currentThread().getName()+"\t come out");
} public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(() ->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.myUnlock();
},"t1").start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} new Thread(() ->{
spinLockDemo.myLock();
spinLockDemo.myUnlock();
},"t2").start();
}
} 结果如下:


独占锁:指该锁一次只能被一个线程所持有,对ReentrantLock和Synchronized而言都是独占锁

共享锁:指该锁可被多个线程所持有,对于ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。

读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的

读写锁分离例子:

class MyReadWrite {
private volatile Map<String, Object> map = new HashMap<>();
//private Lock lock = new ReentrantLock();
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void put(String key, Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t正在写入:" + key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t写入完成:" + key);
} catch (Exception e) {
e.printStackTrace();
}finally {
readWriteLock.writeLock().unlock();
} } public void get(String key) { readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t正在读取:");
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t读取完成:" + result);
} catch (Exception e) {
e.printStackTrace();
}finally {
readWriteLock.readLock().unlock();
} }
} public class ReadWriteLockDemo {
public static void main(String[] args) {
MyReadWrite myReadWrite = new MyReadWrite();
//模拟5个线程读写
for(int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() ->{
myReadWrite.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
} for(int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() ->{
myReadWrite.get(tempInt+"");
},String.valueOf(i)).start();
}
}
} 结果如下:

java 常用锁的更多相关文章

  1. Java常用锁机制简介

    在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制.Java提供了多种多线程锁机制的实现方式,常见的有synchronized.ReentrantLock.Semaphore. ...

  2. 工作常用4种Java线程锁的特点,性能比较、使用场景

    多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...

  3. JAVA常用知识点及面试题总结

    1. String.StringBuffer.StringBuilder三者区别? (1)三者在执行速率上的比较: String<StringBuffer<StringBuilder 原因 ...

  4. Java 常用List集合使用场景分析

    Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让 ...

  5. Java 各种锁的小结

    一. synchronized 在 JDK 1.6 之前,synchronized 是重量级锁,效率低下. 从 JDK 1.6 开始,synchronized 做了很多优化,如偏向锁.轻量级锁.自旋锁 ...

  6. java常用英语单词

    abstract (关键字) 抽象 ['.bstr.kt] access vt.访问,存取 ['.kses]'(n.入口,使用权) algorithm n.算法 ['.lg.riem] annotat ...

  7. JAVA中锁的解决方案

    前言 在上一节中,我们给大家介绍了什么是锁,以及锁的使用场景,我相信大家对锁的定义,以及锁的重要性都有了比较清晰的认识.在这一节中,我们会给大家继续做深入的介绍,介绍JAVA为我们提供的不同种类的锁. ...

  8. Java常用英语汇总(面试必备)

    Java常用英语汇总(面试必备) abstract (关键字)             抽象 ['.bstr.kt] access                            vt.访问,存 ...

  9. Java 常用类库与技巧【笔记】

    Java 常用类库与技巧[笔记] Java异常体系 Java异常相关知识 Java在其创立的时候就设置了比较有效的处理机制,其异常处理机制主要回答了三个问题:what,where,why what表示 ...

随机推荐

  1. Spring激活profile的方式

    Spring中激活profile的方法:设置spring.profiles.active和spring.profiles.default这两个属性 设置激活profile属性的地方(优先级由高到底) ...

  2. linux 位操作

    atomic_t 类型在进行整数算术时是不错的. 但是, 它无法工作的好, 当你需要以原子方 式操作单个位时. 为此, 内核提供了一套函数来原子地修改或测试单个位. 因为整个操作 在单步内发生, 没有 ...

  3. win10 uwp 好看的时间选择控件

    本文告诉大家我找到的好看的时间选择控件 先给大家看一下图,然后就知道我说的是什么 首先需要安装 Nuget ,搜索 DeanChalk.UWP.TimePicker 或输入Install-Packag ...

  4. 在eclipse动态网页项目中,编写web.xml时,servlet标签报错.

    cvc-complex-type.2.4.b: The content of element 'servlet' is not complete. One of '{"http:// jav ...

  5. python3 实现删除数组中相同的元素

    # #把数组中相同的元素去除 # #第一种方式: def del_repeatnum(s=[1,1,1,2,2,3,3,4]): s1=[] for i in s: print(i) if i not ...

  6. HBase 原理

    遗留问题: 数据在更新时首先写入Log(WAL log)和内存(MemStore)中,MemStore中的数据是排序的,当MemStore累计到一定阈值时,就会创建一个新的MemStore,并且将老的 ...

  7. 关于C#异步编程你应该了解的几点建议

    前段时间写了一篇关于C#异步编程入门的文章,你可以点击<C#异步编程入门看这篇就够了>查看.这篇文章我们来讨论下关于C#异步编程几个不成文的建议,希望对你写出高性能的异步编程代码有所帮助. ...

  8. 【萌新向】cartographer_ros最新安装指南 2019-12

    首先说明,这篇文章于2019年12月写下,cartographer现在还在不断更新,也许这篇文档内容会失效,但是大体是一样的安装流程. 一.硬件条件 使用平台 x86_64平台 ROS发行版 Indi ...

  9. pyinstaller打包py脚本Warning:lib not found等相关问题

    小爬从使用Pyinstaller打包py为exe文件以来,一直都会碰到Warning:lib not found等相关问题,诸如: 虽然大多数时候,您像我一样忽略这些warning,打包后的exe也能 ...

  10. [梁山好汉说IT] 容器概念在北宋社会的应用

    [梁山好汉说IT] 容器概念在北宋社会的应用 0x00 摘要 如何对没有软件开发经验的人解释容器? 集装箱真的能够完美解释容器嘛? 除了集装箱还有其他常见实体能够解释容器嘛? 我找到了一个能够 和集装 ...