zoukankan      html  css  js  c++  java
  • java 常用锁

    公平锁和非公平锁

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

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

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

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

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


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

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

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

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

    例子:

    class Photo implements Runnable{

    public synchronized void sendSMS() throws Exception {
    System.out.println(Thread.currentThread().getName()+" invoked sendSMS()");
    sendEmail();
    }

    public synchronized void sendEmail() throws Exception {
    System.out.println(Thread.currentThread().getName()+" invoked sendEmail()");
    }

    @Override
    public void run() {
    get();
    }
    Lock lock = new ReentrantLock();

    public void get() {
    lock.lock();
    try {
    System.out.println(Thread.currentThread().getName()+" invoked sendSMS()");
    set();
    } finally {
    lock.unlock();
    }
    }

    public void set() {
    lock.lock();
    try {
    System.out.println(Thread.currentThread().getName()+" 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()+" come in");
    while (!atomicReference.compareAndSet(null,thread)){

    }
    }

    public void myUnlock() {
    Thread thread = Thread.currentThread();
    atomicReference.compareAndSet(thread,null);
    System.out.println(Thread.currentThread().getName()+" 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() + " 正在写入:" + key);
    try {
    TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    map.put(key, value);
    System.out.println(Thread.currentThread().getName() + " 写入完成:" + 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() + " 正在读取:");
    try {
    TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    Object result = map.get(key);
    System.out.println(Thread.currentThread().getName() + " 读取完成:" + 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();
    }
    }
    }

    结果如下:

  • 相关阅读:
    重写分词器
    twitterfeed
    What is WSGI?
    lucene 3.3一元切分查询例子
    How to Import Your Blog to Facebook Automaticly Using Notes
    协同过滤 学习笔记
    Python入门练习(一):基于全切分,一元语法模型的汉语分词
    test blog sync to qq microblogging
    solr的用分布式搜索(转)
    盘古分词功能简介
  • 原文地址:https://www.cnblogs.com/liuyi13535496566/p/12130300.html
Copyright © 2011-2022 走看看