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对象锁在内存中的对象头中记录
可以看到对象头中有2位表示当前对象是否被锁着,偏向锁/轻量级锁/重量级锁 是java迭代过程中增加出的,在此处,简单理解就是 如果此对象被synchronized 锁住,那么锁标志位就是10,当其他线程获取此对象锁时,java虚拟机检测此标志位,就会阻塞另外的进程
从更加底层来看,synchronized时靠操作系统的Mutex Lock来实现的
4:为什么出现锁?以及什么时候使用锁?
存在多线程操作一些业务资源时,需要控制代码时序,我们需要在保证一定业务时序时,需要使用锁
5:锁的三大特性
原子性,有序性,可见性