Java 锁和相关理解

1:java中锁的种类分几种?什么是公平锁/非公平锁?

java 中对于锁有多中维度的分类,比较常见的有公平锁/非公平锁,可重入锁,独享锁/共享锁,互斥锁/读写锁,实现锁的方式也有多种方式,如通过synchronized 关键字,通过ReentrantLock api等方式。

公平锁和非公平锁,简单理解就是在多线程执行的环境中,2个线程竞争同一把锁的时候,2个线程在针对获取锁的时候,时不公平的,即同一时刻2个线程能同时竞争,锁会被随机授予其中一方,并没有任何规律,至少从高级语言看时这样的效果,公平锁则反之,也就是会根据我们申请锁的时间来授予不同的线程

java中的关键字synchronized实现的就是非公平锁,ReentrantLock默认是非公平锁,可以通过构造函数指定成公平锁,所以如果有需求需要实现锁的竞争是公平关系时,不能使用synchronized关键字

请看下面代码实现

package com.test.java;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    MyThread2 thread2;
    MyThread1 thread1;
    int threadLoopCount = 10;
    Object lock = new Object();
    public TestLock() {
        thread1 = new MyThread1("test_thread1");
        thread2 = new MyThread2("test_thread2");
    }

    //测试非公平锁
    public void testLock1(){
        thread1.start();
        thread2.start();
    }

  
  //简单实现2个自定义Thread类,在2个自定义的Thread中,分别竞争同一把锁lock,每一个循环循环100次,分别看对锁的获取情况
    public class MyThread2  extends Thread{

        public MyThread2(String name) {
            super(name);
        }

        @Override
        public void run() {
            for (int i = 0; i<threadLoopCount ;i++){
                System.out.println("i = " + i +" " +  thread1.getName() + " will get lock");
                synchronized (lock){
                    System.out.println("i = " + i +" " +  thread1.getName() + " have lock,and will sleep");
                    try {
                        Thread.sleep(10);
                        System.out.println("i = " + i + " " +    thread1.getName() + "  sleep end");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("i = " + i + " " +  thread1.getName() + " release lock");
                }
            }
        }
    }


    public class MyThread1  extends Thread{

        public MyThread1(String name) {
            super(name);
        }

        @Override
        public void run() {
            for (int i = 0; i< threadLoopCount ;i++){
                System.out.println("i = " + i +" " +   thread2.getName() + " will get lock");
                synchronized (lock){
                    System.out.println("i = " + i + " " +   thread2.getName() + " have lock,and will sleep");
                    try {
                        Thread.sleep(10);
                        System.out.println("i = " + i + " " +   thread2.getName() + " sleep end");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("i = " + i + " " +   thread2.getName() + " release lock");
                }
            }
        }
    }
}

针对上面的代码进行运行,得到下面结果

i = 0 test_thread1 will get lock 
i = 0 test_thread2 will get lock //test_thread1 和test_thread2 第一次 竞争锁
i = 0 test_thread1 have lock,and will sleep //test_thread1获得锁,test_thread2等待
i = 0 test_thread1  sleep end
i = 0 test_thread1 release lock
i = 1 test_thread1 will get lock //test_thread1 第二次  和test_thread2 第一次 竞争锁
i = 0 test_thread2 have lock,and will sleep //test_thread2 获得锁,test_thread1 等待
i = 0 test_thread2 sleep end
i = 0 test_thread2 release lock
i = 1 test_thread2 will get lock  //test_thread1 第二次  和test_thread2 第二次 竞争锁
i = 1 test_thread2 have lock,and will sleep //test_thread2第二次 循环 获得锁,test_thread1第二次循环 等待
i = 1 test_thread2 sleep end
i = 1 test_thread2 release lock
i = 2 test_thread2 will get lock //test_thread1 第二次  和test_thread2 第三次 竞争锁
i = 2 test_thread2 have lock,and will sleep //test_thread2 第三次循环 获得锁  和 test_thread1 第二次 循环等待
i = 2 test_thread2 sleep end
i = 2 test_thread2 release lock
i = 3 test_thread2 will get lock
i = 3 test_thread2 have lock,and will sleep
i = 3 test_thread2 sleep end
i = 3 test_thread2 release lock
i = 4 test_thread2 will get lock
i = 1 test_thread1 have lock,and will sleep
i = 1 test_thread1  sleep end
i = 1 test_thread1 release lock
i = 2 test_thread1 will get lock
i = 4 test_thread2 have lock,and will sleep
i = 4 test_thread2 sleep end
i = 4 test_thread2 release lock
i = 5 test_thread2 will get lock
i = 2 test_thread1 have lock,and will sleep
i = 2 test_thread1  sleep end
i = 2 test_thread1 release lock
i = 3 test_thread1 will get lock
i = 5 test_thread2 have lock,and will sleep
i = 5 test_thread2 sleep end
i = 5 test_thread2 release lock
i = 6 test_thread2 will get lock
i = 6 test_thread2 have lock,and will sleep
i = 6 test_thread2 sleep end
i = 6 test_thread2 release lock
i = 7 test_thread2 will get lock
i = 7 test_thread2 have lock,and will sleep
i = 7 test_thread2 sleep end
i = 7 test_thread2 release lock
i = 8 test_thread2 will get lock
i = 3 test_thread1 have lock,and will sleep
i = 3 test_thread1  sleep end
i = 3 test_thread1 release lock
i = 4 test_thread1 will get lock
i = 8 test_thread2 have lock,and will sleep
i = 8 test_thread2 sleep end
i = 8 test_thread2 release lock
i = 9 test_thread2 will get lock
i = 9 test_thread2 have lock,and will sleep
i = 9 test_thread2 sleep end
i = 9 test_thread2 release lock
i = 4 test_thread1 have lock,and will sleep
i = 4 test_thread1  sleep end
i = 4 test_thread1 release lock
i = 5 test_thread1 will get lock
i = 5 test_thread1 have lock,and will sleep
i = 5 test_thread1  sleep end
i = 5 test_thread1 release lock
i = 6 test_thread1 will get lock
i = 6 test_thread1 have lock,and will sleep
i = 6 test_thread1  sleep end
i = 6 test_thread1 release lock
i = 7 test_thread1 will get lock
i = 7 test_thread1 have lock,and will sleep
i = 7 test_thread1  sleep end
i = 7 test_thread1 release lock
i = 8 test_thread1 will get lock
i = 8 test_thread1 have lock,and will sleep
i = 8 test_thread1  sleep end
i = 8 test_thread1 release lock
i = 9 test_thread1 will get lock
i = 9 test_thread1 have lock,and will sleep
i = 9 test_thread1  sleep end
i = 9 test_thread1 release lock

从单次上面运行结果看,test_thread2 后面和test_thread1 竞争锁时,经常得到锁,导致 test_thread2优先循环完成10次 后面 test_thread1 完成5到10次的循环

上面的代码也同时说明 Thread 在sleep的时候 并不释放锁的资源,会带着锁 一直休眠,直到休眠结束,同等情况下,Object的关键字 wait 在执行的时候会释放锁,将锁的资源释放出去之后其他线程也可获取锁,wait和sleep的相同点是 都会释放CPU资源

2:什么是可重入锁?

简单理解就是 在一个线程中 如果在获取了锁的代码块中,在继续获取当前的对象锁,是可以获取到的,就是可重入,否则就是不可重入,直接阻塞。不可重入锁,如果继续获取就会发生死锁。

简单写段代码看下

package com.test.java;

public class TestLock {

    MyThread3 thread3;
    int threadLoopCount = 10;
    Object lock = new Object();
    public TestLock() {
       thread3 = new MyThread3("test_thread3");
    }



    //测试锁的重入性
    public void testLock2(){
        thread3.start();
    }


    public class MyThread3 extends Thread{

        public MyThread3(String name) {
            super(name);
        }

        @Override
        public void run() {

            for (int i = 0;i< 3;i++ ){
                System.out.println(thread3 + " will get lock" );
                synchronized (lock){
                    System.out.println(thread3.getName()  + " first get lock,and will sleep" );
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(thread3.getName()  + "   sleep end" );

                    getSecondLock();
                }
            }
        }

        private void getSecondLock(){
            System.out.println(thread3.getName()  + "  getSecondLock begin" );
            synchronized (lock){
                System.out.println(thread3.getName()  + "  getSecondLock  and sleep" );
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(thread3.getName()  + "  getSecondLock  release second lock" );
            }
        }
    }
}


查看下结果

Thread[test_thread3,5,main] will get lock  //最外层获取锁
test_thread3 first get lock,and will sleep  //最外层已经获取到锁
test_thread3   sleep end
test_thread3  getSecondLock begin //获取第二层锁
test_thread3  getSecondLock  and sleep
test_thread3  getSecondLock  release second lock //释放第二层锁
Thread[test_thread3,5,main] will get lock
test_thread3 first get lock,and will sleep
test_thread3   sleep end
test_thread3  getSecondLock begin
test_thread3  getSecondLock  and sleep
test_thread3  getSecondLock  release second lock
Thread[test_thread3,5,main] will get lock
test_thread3 first get lock,and will sleep
test_thread3   sleep end
test_thread3  getSecondLock begin
test_thread3  getSecondLock  and sleep
test_thread3  getSecondLock  release second lock

3:这几种锁的底层原理是什么?从汇编层面看锁的实现和从cpu和操作系统层面角度看锁的实现原理是什么?

java 层面的关键字 synchronized关键字 实现原理是 一旦锁住一个对象,此java对象锁在内存中的对象头中记录

java锁理解.png

可以看到对象头中有2位表示当前对象是否被锁着,偏向锁/轻量级锁/重量级锁 是java迭代过程中增加出的,在此处,简单理解就是 如果此对象被synchronized 锁住,那么锁标志位就是10,当其他线程获取此对象锁时,java虚拟机检测此标志位,就会阻塞另外的进程

从更加底层来看,synchronized时靠操作系统的Mutex Lock来实现的

4:为什么出现锁?以及什么时候使用锁?

存在多线程操作一些业务资源时,需要控制代码时序,我们需要在保证一定业务时序时,需要使用锁

5:锁的三大特性

原子性,有序性,可见性

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容