多线程的锁(六)

简介: 多线程的锁(六)

一. 锁


锁,是在同步时一个非常重要的概念, 然而注意,锁很容易造成死锁。 如果同步了一个对象的内部,又同步了另外一个对象,那么就很容易造成死锁。 然而,如果在同步了一个对象的内部,又同步了当前的对象,那么会造成死锁吗?


public class Lock1 {
    public void test() throws Exception{
        new Thread(()->{
            //同步当前对象
            synchronized (this){
                while(true){
                    //锁同一个对象,可以执行第二个同步的代码。
                    synchronized (this){
                        System.out.println("进入");
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
    public static void main(String[] args) {
        try {
            new Lock1().test();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


运行程序, 查看控制台输出


20200620090826335.png


并不会造成死锁, 说明在同步对象的内部,可以再次同步当前对象。


二. 实现锁


锁,实际上内部就是一个标识, 如果锁上了,那么标识为true,如果解锁,那么标识就是false.


锁有两种形式, 第一种是已经锁上了,无论是谁,包括它自己,都无法再上锁(非重入锁)。


第二种是已经上锁了, 除了它自己之外,其他的线程都不能上锁(重入锁)。


第一种情况,在上锁时,先检测一下标识,如果已经锁上了,标识已经为true了, 那么就不能重新上锁了,必须等待。


第二种情况,在上锁时,先检测一下标识,如果已经锁上了,并且锁上的线程并不是自己,那么就不能重新上锁,必须等待。


二.一 非重入锁


public class Lock2 {
    private Lock lock=new Lock();
    //进行加锁和去锁
    public void a(){
        lock.lock();
        //去调用另一个加锁的方法
        doSomThing();
        lock.unlock();
    }
    public void doSomThing(){
        lock.lock();
        System.out.println("做一些事情");
        lock.unlock();
    }
    public static void main(String[] args) {
        Lock2 lock2=new Lock2();
        lock2.a();
    }
}
/**
 * 锁类
 */
class Lock{
    //有一个标识
    private boolean flag=false;
    public synchronized  void lock(){
        //已经上锁了,那么就必须等待。
        while(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        flag=true;
    }
    public synchronized void unlock(){
        flag=false;
        notify();
    }
}


运行程序,没有任何的输出,发现,程序进入了死锁。


20200620090833500.png


二.二 重入锁


重入锁里面有三个标识,一个是 是否锁的标识 flag, 一个是锁的那个线程,另外一个是锁的次数。


public class Lock3 {
    private ReLock lock=new ReLock();
    //进行加锁和去锁
    public void a(){
        lock.lock();
        //1
        System.out.println(lock.getCount());
        doSomThing();
        //1
        System.out.println(lock.getCount());
        lock.unlock();
        //0
        System.out.println(lock.getCount());
    }
    public void doSomThing(){
        lock.lock();
        System.out.println("做一些事情");
        //2
        System.out.println(lock.getCount());
        lock.unlock();
        //1
        System.out.println(lock.getCount());
    }
    public static void main(String[] args) {
        Lock3 lock3=new Lock3();
        lock3.a();
        //0
        System.out.println(lock3.lock.getCount());
       // lock2.doSomThing();
    }
}
/**
 * 重入锁
 */
class ReLock{
    //有一个标识位
    private boolean flag=false;
    //记录一下,锁的那个线程
    private Thread localLockThread=null;
    //记录一下,锁的次数
    private int count=0;
    public synchronized  void lock(){
        Thread temp=Thread.currentThread();
        //已经锁上了,并且不是当前的线程,那么就等待了。
        while(flag&&temp!=localLockThread){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //赋值
        localLockThread=temp;
        count++;
        flag=true;
    }
    public synchronized void unlock(){
        Thread temp=Thread.currentThread();
        //如果相同,才可以解锁。
        if(localLockThread==temp){
            count--;
            //如果已经没有次数了,那么才是真正的释放锁。
            if(count==0){
                localLockThread=null;
                flag=false;
                notify();
            }
        }
    }
    public int getCount() {
        return count;
    }
}


运行程序


20200620090855578.png


三. 多线程提供锁 ReentrantLock


多线程提供了锁, ReentrantLock , 用法基本与 ReLock 差不多。


关于 ReentrantLock 的用法,后面老蝴蝶会讲解的, 现在只讲解一下实现锁的小例子。


public class Lock4 {
    //内部封装了 标识,线程和次数
    private ReentrantLock lock=new ReentrantLock();
    public void a(){
        lock.lock();
        System.out.println(lock.getHoldCount());
        doSomeThing();
        System.out.println(lock.getHoldCount());
        lock.unlock();
        System.out.println(lock.getHoldCount());
    }
    public void doSomeThing(){
        lock.lock();
        System.out.println(lock.getHoldCount());
        System.out.println("做一些事件");
        lock.unlock();
        System.out.println(lock.getHoldCount());
    }
    public static void main(String[] args) {
       Lock4 lock4=new Lock4();
       lock4.a();
        System.out.println(lock4.lock.getHoldCount());
    }
}


运行程序,


20200620090903727.png


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

相关文章
|
4月前
|
安全 Java 编译器
线程安全问题和锁
本文详细介绍了线程的状态及其转换,包括新建、就绪、等待、超时等待、阻塞和终止状态,并通过示例说明了各状态的特点。接着,文章深入探讨了线程安全问题,分析了多线程环境下变量修改引发的数据异常,并通过使用 `synchronized` 关键字和 `volatile` 解决内存可见性问题。最后,文章讲解了锁的概念,包括同步代码块、同步方法以及 `Lock` 接口,并讨论了死锁现象及其产生的原因与解决方案。
112 10
线程安全问题和锁
|
4月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
51 2
|
27天前
|
Java 关系型数据库 MySQL
【JavaEE“多线程进阶”】——各种“锁”大总结
乐/悲观锁,轻/重量级锁,自旋锁,挂起等待锁,普通互斥锁,读写锁,公不公平锁,可不可重入锁,synchronized加锁三阶段过程,锁消除,锁粗化
|
2月前
|
供应链 安全 NoSQL
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
48 6
|
4月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
|
3月前
|
运维 API 计算机视觉
深度解密协程锁、信号量以及线程锁的实现原理
深度解密协程锁、信号量以及线程锁的实现原理
57 2
|
3月前
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
66 0
|
5月前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
3月前
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
37 0
|
3月前
|
Java API
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
52 0