美文网首页项目
Java开发中的各种锁概念

Java开发中的各种锁概念

作者: __y | 来源:发表于2018-12-18 18:23 被阅读19次

前言:
本文不会深入不会深入!科普文,就是归纳一下平时我们遇到的各种锁,这样听到也不会太懵逼。真正深入的还是要看书的~
在Java开发中,特别是并发编程的时候我们会和很多的锁打交道。写下一篇笔记记录一下各种锁的概念。

1.死锁

在学习操作系统,或者并发编程中的时候我们经常会遇到死锁的概念。什么是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
举个简单的例子:
一个线程需要抢占A锁去执行某段代码,抢占到了A锁后,要抢占B锁去继续执行代码。另外一个线程则需要抢占B锁,然后抢占A锁去执行代码。这样就会造成彼此之间阻塞。两个线程一起卡死。
如何解决?

  • 避免写嵌套锁(废话);
  • 规范嵌套锁的顺序,多个线程用户同一个顺序并且放在同一个方法里;
  • 引入超时机制(需要用到显示锁Lock)

2.显示锁,公平锁,可重入锁

标题中的说的三种锁说的就是Lock这个接口下的锁,Lock具有这三种概念。
显示锁:非Java给我们提供的关键字去操作。而是我们自己定义锁,然后显示的获取,显示的释放。
公平锁:一定程度上保证线程获得这个锁的机会是公平的。但是这样会大大消耗性能。
可重入锁:看下面的代码。这两个是同步代码块。他们获取的是同一把锁。因此获取锁的是线程,不是对象。因此在线程没有结束之前,这把锁可以一直使用。
PS:Lock下的ReentrantLock也具有可重入性。

public class Widget {
    // 获得了锁
    public synchronized void doSomething() {
        ...
    }
}

public class LoggingWidget extends Widget {

    // 获得了锁
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}

3.Lock的介绍

其实synchronize从jdk一直发展到现在,性能已经非常好。如果不是很有必要还是建议synchronize;因为简单易用。不过这里还是要说一下Lock。下面是这个接口的方法。

image.png
  • lock:获得锁

  • lockInterruptibly:可打断锁

  • tryLock:尝试获取锁。

  • tryLock带时间:引入超时机制。很大程度上可以避免死锁

  • unlock():释放锁

看上去是非常爽的。也非常的优雅,毕竟啥时候加锁上锁的控制权在我们这里了。但是如果我们忽略了释放锁,或者说程序出了点问题,这个锁没有释放。那就麻烦大了~因此还是要酌情使用!

怎么用呢?这里给一个demo

class LockDemo {
    private final ReentrantLock lock = new ReentrantLock();
    // ...

    public void m() { 
        lock.lock();  // block until condition holds
        try {
            // ... method body
        } finally {
            lock.unlock()
        }
    }
}


4.ReentrantReadWriteLock

ReentrantReadWriteLock是一个读写锁

  • 取数据的时候,可以多个线程同时进入到到临界区(被锁定的区域)
  • 数据的时候,无论是读线程还是写线程都是互斥
    当我们读的操作比较多。写的操作比较少的时候可以用ReentrantReadWriteLock。
    ReentrantReadWriteLock就两个方法:
  • readLock():得到一个可以被多个读操作共用的毒锁。但是用会排斥所有写操作
  • writeLock():得到一个写锁。排斥其他所有读操作和写操作
    举个例子
    读锁:
package com.lock;

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

public class LockTest2 {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        final LockTest2 lockTest2 = new LockTest2();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lockTest2.get(Thread.currentThread());
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lockTest2.get(Thread.currentThread());
            }
        }).start();
    }

    public void get(Thread thread) {
        try {
            lock.readLock().lock();
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start <= 1) {
                System.out.println(thread.getName() + "正在进行读操作");
            }
            System.out.println(thread.getName() + "操作完毕");

        }catch (Exception e) {

        }
        finally {
            lock.readLock().unlock();
        }
    }

}
image.png

我们可以看到是交替进行的~
写锁:
写锁只有将readLock改成writeLock就好了。这里不贴代码了。直接观察结果可以看出是互斥的。必须一个个来


image.png

5.悲观锁,乐观锁

悲观锁,乐观锁也是我们并发编程中常遇到的问题。在数据库层面有为体现。
下面举例子说明:

image.png
假设现在有两个线程:
A线程来了,读到了这个数据,status为0;B线程改为了1了。由于数据库的事务隔离机制。并发修改了这个数据。那数据就混乱了。
这个时候就要保持互斥性,同一个时间只能有一个线程来操作这行数据。
解决方案:
乐观锁:
加一个字段版本字段:
A线程读出来的时候版本号位1,然后更新的时候加个条件update xxx where version =1;但是B线程已经改为了2,所以会更新失败;这样就可以控制并发修改。一般是给用户提示,有人已经操作了数据。但是还是可以读取这一行数据
悲观锁
SQL关键字FOR_UPDATE
select * from XXXX FOR_UPDATE
把查询出来的数据锁住了,其他人读这条数据会阻塞。在用户界面上会转圈会等待。
举例:
比如外卖。用户下了一个单,这个时候订单的数据异步到配送端了。此时,用户突然申请退单了。此时数据库订单状态应该是退单状态。然而由于时差,订单的数据才到配送端。此时配送人员又抢单成功将订单状态重新改为了配送中(实际上这张订单应该是退单状态的。)

6.分布式锁

我们知道乐观锁,悲观锁是数据库层面(单个)。如果我们分库分表的话我们怎么处理呢?这个时候我们就要用分布式锁。
我们可以用zookeeper,redis实现~具体实现大家可以baidu一下!

相关文章

  • Java开发中的各种锁概念

    前言:本文不会深入不会深入!科普文,就是归纳一下平时我们遇到的各种锁,这样听到也不会太懵逼。真正深入的还是要看书的...

  • Java中各种锁的介绍

    ​ Java中各种锁的介绍 前言 Java提供了各种各样的锁,每种锁...

  • 轻松搞懂Java中的自旋锁

    前言 在之前的文章《一文彻底搞懂面试中常问的各种“锁”》中介绍了Java中的各种“锁”,可能对于不是很了解这些概念...

  • Java 中的各种锁

    多线程开发离不开各种锁,下面总结下Java和JDK提供的各种锁机制 synchronized synchroniz...

  • Java中的各种锁

    一个线程中的多个流程能不能获取同一把锁:可重入锁和非可重入锁 可重入锁 可重入性:表明了锁的分配机制,是基于线程的...

  • java中的各种锁

    一. 按照性质 1. 公平锁/非公平锁 公平锁是指等待时间最长的会先获得锁,等待时间短的后获得锁;而非公平锁则不一...

  • java中的各种锁

    懂得 1.公平锁和非公平锁 公平锁是指多个线程在等待同一个锁时,必须按照申请锁的先后顺序来一次获得锁。公平锁的好处...

  • Java中的各种锁

    转自公众号Java建设者 ,作者cxuan Java 锁分类 Java 中的锁有很多,可以按照不同的功能、种类进行...

  • java中各种锁结合源码深度解析

    java中各种锁介绍 1.公平锁 / 非公平锁 公平锁 在java代码中类名是FairSync。 公平锁是指多个线...

  • Java 中锁的概念

    了解各种锁的概念对并发编程很有帮助,本文将记录几种常见的锁概念。 乐观锁与悲观锁 悲观锁 是指对数据的修改持保守态...

网友评论

    本文标题:Java开发中的各种锁概念

    本文链接:https://www.haomeiwen.com/subject/veolkqtx.html