码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA锁

时间:2019-12-30 09:54:13      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:nbsp   null   ati   维护   线程池   code   onclick   alt   阻塞   

一、公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁

  1. 公平锁和非公平锁:

    1.1 是什么?

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

非公平锁:是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获得锁;在高并发的情况下,有可能会造成优先级反转或者饥饿现象;

    1.2 两者区别?

公平锁/非公平锁:

  并发包ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁;

关于两者的区别:

  公平锁,就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从从队列中取到自己;

  非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就在采用类似公平锁的那种方式;

    1.3 题外话?

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

  2. 可重入锁(又名递归锁):

    2.1 是什么?

可重入锁也叫递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,同一个线程在外层方法获取锁的时候,在进入内层方法的时候会自动获取锁。也就是说,线程可以进入任何一个它已经拥有锁所同步着的代码块

    2.2 ReentrantLock/Synchronized就是一个典型的可重入锁

    2.3 可重入锁最大的作用是避免死锁

参考代码1:Synchronized

技术图片
package com.example.code.lock;

class Phone {
    public synchronized void sendSMS() {
        System.out.println(Thread.currentThread().getName() + "\t invoked sendSMS()");
        this.sendEmail();
    }
    public synchronized void sendEmail() {
        System.out.println(Thread.currentThread().getName() + "\t invoked sendEmail()");
    }
}

/**
 * 同步方法可以调用另一个同步方法
 * 0     invoked sendSMS()      //0线程在外层方法获取锁的时候
 * 0     invoked sendEmail()    //0在进入内层方法的时候会自动获取锁
 * 1     invoked sendSMS()
 * 1     invoked sendEmail()
 */
public class LockDemo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {phone.sendSMS();},String.valueOf(i)).start();
        }
    }
}
View Code

参考代码2:ReentrantLock

技术图片
package com.example.code.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Phone {
    public void sendSMS() {
        System.out.println(Thread.currentThread().getName() + "\t invoked sendSMS()");
        this.sendEmail();
    }
    public void sendEmail() {
        System.out.println(Thread.currentThread().getName() + "\t invoked sendEmail()");
    }
}

/**
 * ReentrantLock是典型的可重入锁
 * 注意:锁几次释放几次
 */
public class LockDemo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Lock lock = new ReentrantLock();
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                lock.lock();
                lock.lock();
                try {
                    phone.sendSMS();
                }finally {
                    lock.unlock();
                    lock.unlock();
                }
            }, String.valueOf(i)).start();
        }
    }
}
View Code

  3. 自旋锁:

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

技术图片

 

 案例:手写自旋锁

技术图片
package com.example.code.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 题目:实现一个自旋锁
 * 自旋锁的好处:循环比较获取直到成功为止,没有类似wait的阻塞。
 *
 * 通过CAS完成自旋锁,A线程先进来调用myLock方法自己持有5秒钟,B随后进来后发现当前线程拥有锁,表示null,所以只能通过自选等待,直到A释放锁后B随后抢到
 */
public class SpinLockDemo {
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    public void myLock() {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + "\t come in o(n_n)o");
        while (!atomicReference.compareAndSet(null, thread)) {}
    }
    public void myUnlock() {
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread, null);
        System.out.println(thread.getName() + "\t invoked myUnlock()");
    }
    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                spinLockDemo.myLock();
                try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
                spinLockDemo.myUnlock();
            },String.valueOf(i)).start();
        }
    }
}
View Code

 

  4. 独占锁/共享锁:

 

二、CountDownLatch/CyclicBarrier/Semaphore使用过吗?

 

三、阻塞队列知道吗?

 

四、线程池用过吗?ThreadPoolExecutor谈谈你的理解?

 

五、线程池用过吗?生产上你如何设置合理参数?

 

六、死锁编码及定位分析?

JAVA锁

标签:nbsp   null   ati   维护   线程池   code   onclick   alt   阻塞   

原文地址:https://www.cnblogs.com/luliang888/p/12117454.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!