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

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

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:锁的三大特性

原子性,有序性,可见性

你可能感兴趣的:(Java 锁和相关理解)