java 常用锁

公平锁和非公平锁

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();            }        }    }

结果如下:

原文地址:https://www.cnblogs.com/liuyi13535496566/p/12130300.html

时间: 2024-10-10 02:58:47

java 常用锁的相关文章

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

Java常用英语汇总(面试必备) abstract (关键字)             抽象 ['.bstr.kt] access                            vt.访问,存取 ['.kses]‘(n.入口,使用权) algorithm                     n.算法 ['.lg.riem] annotation                     [java]代码注释 [.n.u'tei..n] anonymous                

java常用英语单词

abstract (关键字) 抽象 ['.bstr.kt] access vt.访问,存取 ['.kses]'(n.入口,使用权) algorithm n.算法 ['.lg.riem] annotation [java]代码注释 [.n.u'tei..n] anonymous adj.匿名的[.'n.nim.s]' (反义:directly adv.直接地,立即[di'rektli, dai'rektli]) apply v.应用,适用 [.'plai] application n. 应 用 ,

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

Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让你清楚明白,为什么工作中会常用ArrayList和CopyOnWriteArrayList?了解底层实现原理,我们可以学习到很多代码设计的思路,开阔自己的思维.本章通俗易懂,还在等什么,快来学习吧! 知识图解: 技术:ArrayList,LinkedList,Vector,CopyOnWriteAr

java常用设计模式(一)单例模式

第一次写博客,也是第一篇,从单例模式开始,不足之处,望各位看官海涵. 简介 首先我们都知道单例模式是java常用的23种设计模式之一,它的用途可谓是非常广泛.它的核心就在于单实例,即整个环境中该类有且只能有一个对象.而java创建实例的方式已知的有四种,分别是通过new.clone.反射或者序列化这四种方式去创建实例,怎样保证单例呢,下面且听我一一道来. 单例模式的常见写法: 1.基础饿汉式单例 优点: 类加载时就去初始化,没有线程安全问题,不能通过new创建实例 缺点: ①.能通过反射或者序列

Java偏向锁实现原理(Biased Locking)

阅读本文的读者,需要对Java轻量级锁有一定的了解,知道lock record, mark word之类的名词.可以参考我的一篇博文:Java轻量级锁原理详解(Lightweight Locking) Java偏向锁(Biased Locking)是Java6引入的一项多线程优化.它通过消除资源无竞争情况下的同步原语,进一步提高了程序的运行性能. 轻量级锁也是一种多线程优化,它与偏向锁的区别在于,轻量级锁是通过CAS来避免进入开销较大的互斥操作,而偏向锁是在无竞争场景下完全消除同步,连CAS也不

java 常用工具

System:类中的属性方法都是静态的.无法实例化 err:"标准"错误输出流 in:"标准"输入流 out:"标准"输出流 常见方法: long currentTimeMillis();获取当前时间的毫秒值 Properties    getProperties(); 获取系统属性 Properties集合中存储的都是String类型的键和值. Runtime:没有构造方法摘要,说明该类不可以创建对象. 方法又是非静态,说明该类提供静态返回该类

synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解

本Blog分为例如以下部分: 第一部分:synchronized与static synchronized 的差别 第二部分:JVM底层又是怎样实现synchronized的 第三部分:Java多线程锁,源码剖析 第一部分:synchronized与static synchronized的差别 1.synchronized与static synchronized 的差别 synchronized是对类的当前实例进行加锁,防止其它线程同一时候訪问该类的该实例的全部synchronized块.注意这里

java常用正则表达式

java常用正则表达式 1.^\d+$ //匹配非负整数(正整数 + 0) 2.^[0-9]*[1-9][0-9]*$ //匹配正整数 3.^((-\d+) ?(0+))$ //匹配非正整数(负整数 + 0) 4.^-[0-9]*[1-9][0-9]*$ //匹配负整数 5.^-?\d+$ //匹配整数 6.^\d+(\.\d+)?$ //匹配非负浮点数(正浮点数 + 0) 7.^(([0-9]+\.[0-9]*[1-9][0-9]*) ?([0-9]*[1-9][0-9]*\.[0-9]+)

java常用100例

作了好事受到职责而坚持下去,这才是奋斗的本色.--巴尔扎克 本讲内容:java常用100例 例1:打印金字塔 public class T { public static void main(String[] args){ int lay=10; for(int i=1;i<=lay;i++){//表示层 for(int j=1;j<=lay-i;j++){//找出空格规律 System.out.print(" "); } for(int k=1;k<=i*2-1;k