面试官必问java 并发知识总结-同步与锁

Posted 神技圈子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官必问java 并发知识总结-同步与锁相关的知识,希望对你有一定的参考价值。

同步

对象与锁

  什么叫java同步?就是java用来保证多线程在共享的内存或临界区,能够可以按照可以预期的行为去顺序执行。如果不做这个同步,那么线程的行为就不可以预期。解释这个问题最好的就是给个实践的例子。下面就写个例子来说明存在共享内存在不同步的场景下对 valueCnt++ 操作的结果不可预期:


public class MutiThreadTest {
    
    private int  valueCnt = 0;
    public void  valueCntAdd(){
         valueCnt++;
    }
    
    public int getValueCnt(){
        return valueCnt;
    }
    
    public static void test(int n){
        System.out.println("current is the "+n+" -------------");
        
        MutiThreadTest test = new MutiThreadTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //System.out.println(Thread.currentThread().getName()+"  start");
                System.out.println(Thread.currentThread().getName()+" get valueCnt = "+test.getValueCnt());
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                test.valueCntAdd();
                System.out.println(Thread.currentThread().getName()+" exit ,after add valueCnt = "+test.getValueCnt());

            }
        },"thread111");


        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //System.out.println(Thread.currentThread().getName()+"  start");
                System.out.println(Thread.currentThread().getName()+" get valueCnt = "+test.getValueCnt());
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                }
                test.valueCntAdd();
                System.out.println(Thread.currentThread().getName()+" exit ,after add valueCnt = "+test.getValueCnt());

            }
        },"thread222");

        t2.start();
        t1.start();

        try {
            Thread.sleep(5000);
            System.out.println(" after two thread exit ,the valueCnt="+ test.getValueCnt());
            System.out.println("-----------------------------------------------------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

    public static void main(String[] args) {
       for (int n=0;n<20;n++){
           MutiThreadTest.test(n);
       }
    }
    
}

运行结果如下 

/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=62794:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/tools.jar:/Users/chaoxi.ycx/test/target/classes:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-core/4.3.4.RELEASE/spring-core-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/commons-logging/commons-logging/1.2/commons-logging-1.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar:/Applications/apache-maven-3.5.4/repo/com/alibaba/fastjson/1.2.69_noneautotype/fastjson-1.2.69_noneautotype.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-web/4.3.4.RELEASE/spring-web-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-aop/4.3.4.RELEASE/spring-aop-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-beans/4.3.4.RELEASE/spring-beans-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-context/4.3.4.RELEASE/spring-context-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-expression/4.3.4.RELEASE/spring-expression-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/commons-codec/commons-codec/1.11/commons-codec-1.11.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-collections4/4.2/commons-collections4-4.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/poi/poi-ooxml/4.0.1/poi-ooxml-4.0.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/poi/poi-ooxml-schemas/4.0.1/poi-ooxml-schemas-4.0.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/xmlbeans/xmlbeans/3.0.2/xmlbeans-3.0.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar:/Applications/apache-maven-3.5.4/repo/com/github/virtuald/curvesapi/1.05/curvesapi-1.05.jar MutiThreadTest
current is the 0 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 1
 after two thread exit ,the valueCnt=1
-----------------------------------------------------------
current is the 1 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 2
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 2 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 3 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 2
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 4 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 5 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 6 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 2
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 7 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 1
 after two thread exit ,the valueCnt=1
-----------------------------------------------------------
current is the 8 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 2
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 9 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2

Process finished with exit code 130 (interrupted by signal 2: SIGINT)

 从上面很明显可以看出,经过多线程对 valueCnt做add 操作,最终的valueCnt值是不确定,因为valueCntAdd不是原子的方法

现在我们把  valueCntAdd 前面加上 synchronized 让这个方法同步起来

,再来看下 实验结果如下: 行为基本可控了

/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=49555:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/tools.jar:/Users/chaoxi.ycx/test/target/classes:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-core/4.3.4.RELEASE/spring-core-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/commons-logging/commons-logging/1.2/commons-logging-1.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar:/Applications/apache-maven-3.5.4/repo/com/alibaba/fastjson/1.2.69_noneautotype/fastjson-1.2.69_noneautotype.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-web/4.3.4.RELEASE/spring-web-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-aop/4.3.4.RELEASE/spring-aop-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-beans/4.3.4.RELEASE/spring-beans-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-context/4.3.4.RELEASE/spring-context-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/org/springframework/spring-expression/4.3.4.RELEASE/spring-expression-4.3.4.RELEASE.jar:/Applications/apache-maven-3.5.4/repo/commons-codec/commons-codec/1.11/commons-codec-1.11.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-collections4/4.2/commons-collections4-4.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/poi/poi-ooxml/4.0.1/poi-ooxml-4.0.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/poi/poi-ooxml-schemas/4.0.1/poi-ooxml-schemas-4.0.1.jar:/Applications/apache-maven-3.5.4/repo/org/apache/xmlbeans/xmlbeans/3.0.2/xmlbeans-3.0.2.jar:/Applications/apache-maven-3.5.4/repo/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar:/Applications/apache-maven-3.5.4/repo/com/github/virtuald/curvesapi/1.05/curvesapi-1.05.jar MutiThreadTest
current is the 0 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 1 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 2 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 3 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 4 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 5 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 6 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 7 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 8 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 9 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 10 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 11 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 12 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 13 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 14 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 15 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 16 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 17 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 18 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread111 exit ,after add valueCnt = 1
thread222 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------
current is the 19 -------------
thread222 get valueCnt = 0
thread111 get valueCnt = 0
thread222 exit ,after add valueCnt = 1
thread111 exit ,after add valueCnt = 2
 after two thread exit ,the valueCnt=2
-----------------------------------------------------------

Process finished with exit code 0

     java语言里面每一个Object类及其子类的实例都拥有一个锁。但是8个基本类型:char  int  long  float double  boolean  byte  short  除外 ,如果你想对基本类型做锁功能,可以用起对应的类型包装器类,比如  Integer。但是基本类型的数组也是拥有对象锁的(从另一个层面说明数组是对象 哈哈),但是它的标量元素,还是不具备对象锁属性。Class实例本质上是个对象,所有相同类型的instance实例的类对象都是同一个,所以在在静态同步方法对所有的实例对象都可见。

同步方法和同步块

   了解了同步的概念之后,如果想使用同步一般有两种方式,同步方法或者同步块。这两种方式给个示例大家体会下: 

     1)同步方法    

	public synchronized void method(){
		/*这是同步方法示例*/
		//step1
		//step2
		//step3
		
	}

 

2)同步块示例 

	public void block(){
		/*这是同步方法示例*/
		//step1
		synchronized(this){
			
			
		}
		
		//step2
		//step3
		
	}

通过上面的对比可以看到,同步方法锁定的范围更大,同步代码块锁定的可能只是方法的一部分,所以一般尽可能用同步方法块,效率更高。这里需要注意一个点 所以你吃synchronized 关键字不是方法签名范围,所以不能被继承。比如 类A.java  有一个同步方法   synchronized  method(){},  B extends  A , 那么 B里面的method()是不具备synchronized 属性的。


等待锁与释放锁

     synchronized关键字跟锁的机制原理相同,都是要持有锁释放锁。就是你进入一个同步方法或者同步代码块的时候你需要持有锁,当你从一个同步方法或者同步代码块退出的时候,你会释放锁。

     java 里面是允许线程重复进入相同的对象锁而不会被阻塞(如果线程已经获取某个对象锁,那么它不需再次获取对象锁就能访问其他同步在该对象锁的方法)举个例子

                                                                               
public class MutiThreadTest {                                                  
                                                                               
	public synchronized void method1(){                                        
		/*这是同步方法示例*/                                                           
		//step1                                                                
		method2();                                                             
		//step3                                                                
		                                                                       
	}                                                                          
	                                                                           
	public synchronized void method2(){                                        
		/*这是同步方法示例*/                                                           
		//step1                                                                
		//step2                                                                
		//step3                                                                
		                                                                       
	}                                                                          
	                                                                           
	public void method3(){                                                     
		/*这是同步方法示例*/                                                           
		//step1                                                                
		synchronized(this){                                                    
		}                                                                      
	}                                                                          
}                                                                              
                                                                               

      method1 里面调用 method2  不会死锁,因为 method1 被调用的时候,线程已持有 MutiThreadTest 实例对象的锁了。这在C语言里面是行不通的(C语言没有锁重入的概念)。

     当前线程从 method1 退出的时候就会释放锁,这时候其他线程就可以申请这个锁了,但是哪个线程能获取该锁,在java里面没有机制能保证的。也没有办法能够获取这个锁被哪个线程持有。

静态变量/方法

        大家要注意锁是区分对象的概念的,不管是实例对象还是类对象,只针对同步锁所对象的对象实例,不会因为对一个实例对象加锁了,就会对类对象或者这个类的父类对象加锁。如果想让某个方法或者代码块在类对象上同步起来,那么应该把锁换成 类对象。    

        在类锁上做同步,可以通过下面的方式实现: synchronized(ClassName.class) { /*需要同步的动作*/ }

       Java虚拟机在类加载和类初始化阶段,内部获得并释放类锁。除非你要去写一个特殊的类加载器或者需要使用多个锁来控制静态初始顺序,这些内部机制不应该干扰普通类对象的同步方法和同步块的使用。Java虚拟机没有什么内部操作可以独立的获取你创建和使用的类对象的锁。


以上是关于面试官必问java 并发知识总结-同步与锁的主要内容,如果未能解决你的问题,请参考以下文章

面试官必问java 并发知识总结-线程

面试官必问的信号量与生产者消费者问题

大厂面试官必问的Mysql锁机制

面试官必问的 3 道 MQ 面试题,还有谁不会??

字节面试官必问的Mysql锁机制

阿里Java面试答案PDF文档免费领