Java并发之synchronized关键字和Lock接口

欢迎点赞阅读,一同学习交流,有疑问请留言 。
GitHub上也有开源 JavaHouse,欢迎star

引用

当开发过程中,我们遇到并发问题。怎么解决?

一种解决方式,简单粗暴:上锁。将千军万马都给拦下来,只允许一个人过独木桥。书面意思就是将并行的程序变成串行的程序。现实的锁有门锁、挂锁和抽屉锁等等。在Java中,我们的锁就是synchronized关键字和Lock接口。

synchronized关键字

synchronized也叫同步锁,是Java里面的关键字。我们可以猜测到synchronized原理也JVM虚拟机有关联。

synchronized锁的是对象。对象里面有一个叫做监视锁(monitor)的东西,监视锁依赖操作系统的互斥锁(Mutex Lock)。操作系统切换线程其实就是从用户态编程核心态(cpu的两种状态)。这个代价有点高,所以synchronized这个重量级锁后面也引进了偏向锁和轻量级锁。

加锁(监视锁monitor)过程分析():

  1. 当monitor的进入数为0,线程A进入
  2. monitor的进入数为1
  3. 线程B想进入该monitor就会被阻塞。

线程A可以重复进入该monitor,所以synchronized是可重入锁,和Lock实现的锁一样。

  • 程序验证
public class SynchronizedTest {
    private static  int i = 0;
    public static void main(String[] args) {
        test();
    }

    public static void test(){
        synchronized (SynchronizedTest.class){
            synchronized (SynchronizedTest.class){
                i++;
            }
        }
    }
}
  • 运行结果
    程序正常运行,没有报错

synchronized可以修饰方法以及代码块,代码块就是上面重入锁的例子。

  • 修饰方法
public class SynchronizedTest {
    static int n = 100;
    final static CountDownLatch start = new CountDownLatch(n);
    private static  int i = 0;
    public static void main(String[] args) throws InterruptedException {
        for (int j = 0; j < n; j++) {
            Thread thread = new Thread(new addNoSynchronized());
            thread.start();
        }
        start.await();
        System.out.println(i);
    }

    public static class addSynchronized implements Runnable{
        @Override
        public void run() {
            addSynchronized();
        }
        public static synchronized void addSynchronized(){
            for (int j = 0; j < 1000; j++) {
                i++;
            }
            start.countDown();
        }
    }
}
  • 运行结果
100000

如果去掉 synchronized 关键字的话,运行结果大概率不是 100000,因为线程不安全问题。

Lock接口

一般我们使用 ReentrantLock 类作为重入锁,实现Lock接口。

  • 使用方法
public class ReentranLockTest {
    private static int j;
    private static int n = 100;
    private static CountDownLatch latch = new CountDownLatch(n);
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            new Thread(new LockTest()).start();
        }
        latch.await();
        System.out.println("结果为:"+j);
    }

    public static class LockTest implements Runnable{
        static Lock lock = new ReentrantLock();
        @Override
        public void run() {
            lockTest();
            latch.countDown();
        }
        private void lockTest() {
            lock.lock();
            try {
                for (int i = 0; i < 1000; i++) {
                        j++;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}
  • 运行结果
结果为:100000

这里我们锁住的 j++ 这块资源区(公共资源),lock 是 static 关键字修饰的,是类对象,思考一下如果不是类对象会怎么样?那就是连环锁了(看图)。

每一个线程都对可以用钥匙解开这把锁,对于程序而言,加锁操作就没有意义了。因为我们需要的是一个锁。

欢迎关注我的微信公众号

原文地址:https://www.cnblogs.com/chenzhuantou/p/11964787.html

时间: 2024-08-12 21:01:16

Java并发之synchronized关键字和Lock接口的相关文章

Java并发之synchronized关键字深度解析(二)

前言 本文继续[Java并发之synchronized关键字深度解析(一)]一文而来,着重介绍synchronized几种锁的特性. 一.对象头结构及锁状态标识 synchronized关键字是如何实现的给对象加锁?首先我们要了解一下java中对象的组成.java中的对象由3部分组成,第一部分是对象头,第二部分是实例数据,第三部分是对齐填充. 对齐填充:jvm规定对象的起始内存地址必须是8字节的整数倍,如果不够的话就用占位符来填充,此部分占位符就是对齐填充: 实例数据:实例数据是对象存储的真正有

Java多线程:synchronized关键字和Lock

一.synchronized synchronized关键字可以用于声明方法,也可以用来声明代码块,下面分别看一下具体的场景(摘抄自<大型网站系统与Java中间件实践>) 案例一:其中foo1和foo2是SynchronizedDemo1类的两个静态方法.在不同的线程中,这两个方法的调用是互斥的,不仅是它们之间,任何两个不同线程的调用也互斥. public class SynchronizedDemo1 { public synchronized static void foo1(){} pu

Java并发之synchronized关键字深度解析(一)

前言 近期研读路神之绝世武学,徜徉于浩瀚无垠知识之海洋,偶有攫取吉光片羽,惶恐未领略其精髓即隐入岁月深处,遂急忙记录一二,顺备来日吹cow之谈资.本小系列为并发之亲儿子-独臂狂侠synchronized专场. 一.使用场景 synchronized是java中的一个关键字,用于给对象加锁,保证在单机的并发条件下线程安全.原子性和可见性是它保证线程安全的基础功能.一定要注意它锁的是对象,而且它是一个排他的非公平可重入锁.本文先从使用的场景上来展现其作用. 1.用在普通方法中 常用的格式如下所示:

Java并发之synchronized关键字深度解析(三)

前言 本篇主要介绍一下synchronized的批量重偏向和批量撤销机制,属于深水区,大家提前备好氧气瓶. 说完synchronized锁的膨胀过程,下面我们再延伸一下synchronized锁的两种特殊处理,一种是锁的批量重偏向,一种是锁的批量撤销.JVM中有两个参数,BiasedLockingBulkRebiasThreshold和BiasedLockingBulkRevokeThreshold,前者默认阈值为20,控制批量重偏向:后者默认阈值为40,控制批量撤销.下面我们分别看一下它们是如

JAVA并发之synchronized关键字

简介 synchronizaed关键字是JAVA阻塞同步(互斥同步)中最常用的一种方式,使用时将此关键字加到所需同步的代码块儿前即可,比如 int i = 0; synchronized (this){ i++; } synchronizaed同步方式在JAVA中是重量级加锁方式,下面来介绍一下它的工作原理,首先写一段代码: public class Sync { synchronized void syncMethod(){} public void add(){ synchronized (

Synchronized关键字、Lock,并解释它们之间的区别

Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁. Synchronized是悲观锁机制,独占锁.而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止. ReentrantLock适用场景 某个线程在等待一个锁的控制权的这段时间需要中断 需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁

巨人大哥谈Java中的Synchronized关键字用法

巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 

java并发之volatile关键字(TIJ21-21.3.3 21.3.4)

** 1 简介    volatile是java中的一个保留关键字,它在英语中的含义是易变的,不稳定的.volatile像final.static等其他修饰符 一样,可以修饰class中的域,而不能修饰方法中的局部变量.当修饰class中的域时,volatile可以修饰primative类型或者任意对 象.下面这个例子展示了这一点: public class TIJ_volatile {    private volatile int i;    private volatile String

关于Java中的synchronized关键字

[内容简介] 本文主要介绍Java中如何正确的使用synchronized关键字实现线程的互斥锁. [能力需求] 至少已经完整的掌握了Java的语法基础,基本的面向对象知识,及创建并启动线程. [正文] 关于synchronized关键字的使用,很多说法是“锁同一个对象”就可以确保锁是正常的,今天,有人提了一个问题,我觉得非常不错,所以与各位一起分享一下. 在这里,就不提关于线程和synchronized关键字的基本使用了,以非常传统的“银行取钱”的故事为案例,直接上代码:Ps:以下代码是直接敲