synchronized锁重入

来源:互联网 发布:linux怎么写c 编辑:程序博客网 时间:2024/06/07 22:47

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象时是可以再次得到该对象的锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。

// class Servicepublic class Service {    synchronized public void service1() {        System.out.println("service1");        service2();    }    synchronized public void service2() {        System.out.println("service2");        service3();    }    synchronized public void service3() {        System.out.println("service3");        service4();    }    synchronized public void service4() {        System.out.println("service4");    }}// class Thread06public class Thread06 extends Thread{    @Override    public void run() {        super.run();        Service service = new Service();        service.service1();    }}// main class public static void main(String[] args) {    service();}private static void service() {    Thread06 thread = new Thread06();    thread.start();}

输出如下:

service1service2service3service4

“可重入锁”的概念是:自己可以再次获取自己的内部锁。比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。

可重入锁也支持父子类继承的环境中。

// class Suppublic class Sup {    public int i = 10;    synchronized public void operateSupMethod() {        try{            i --;            System.out.println("sup print i=" + i);            Thread.sleep(100);        } catch(InterruptedException e) {            e.printStackTrace();        }    }}// class Subpublic class Sub extends Sup{    synchronized public void operateSubMethod() {        try{            while(i > 0) {                i --;                System.out.println("sub print i=" + i);                Thread.sleep(100);                this.operateSupMethod();            }        } catch(InterruptedException e) {            e.printStackTrace();        }    }}// class Thread07public class Thread07 extends Thread{    @Override    public void run() {        super.run();        Sub sub = new Sub();        sub.operateSubMethod();    }}// main classpublic static void main(String[] args) {    sub();}private static void sub() {    Thread07 thread = new Thread07();    thread.start();}

输出结果:

sub print i=9sup print i=8sub print i=7sup print i=6sub print i=5sup print i=4sub print i=3sup print i=2sub print i=1sup print i=0

从以上结果可以看到,当存在父子类继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法的。

当一个线程执行的代码异常时,其所持有的锁会自动释放。

// class Object01public class Object01 {    synchronized public void testMethod() {        if("a".equals(Thread.currentThread().getName())) {            System.out.println("ThreadName=" + Thread.currentThread().getName()                    + " run beginTime=" + System.currentTimeMillis());            int i = 1;            while(i == 1) {                if(("" + Math.random()).substring(0, 8).equals("0.123456")) {                    System.out.println("ThreadName=" + Thread.currentThread().getName()                            + " run exceptionTime=" + System.currentTimeMillis());                    Integer.parseInt("a");                }            }        } else {            System.out.println("Thread B run Time=" + System.currentTimeMillis());        }    }}// class ThreadCpublic class ThreadC extends Thread{    private Object01 object;    public ThreadC(Object01 object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.testMethod();    }}// class ThreadDpublic class ThreadD extends Thread{    private Object01 object;    public ThreadD(Object01 object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.testMethod();    }}// main classpublic static void main(String[] args) {    object01();}private static void object01() {    try{        Object01 object = new Object01();        ThreadC tc = new ThreadC(object);        tc.setName("a");        tc.start();        Thread.sleep(500);        ThreadD td = new ThreadD(object);        td.setName("b");        td.start();    } catch (InterruptedException e) {        e.printStackTrace();    }}

输出结果:

ThreadName=a run beginTime=1496548324461ThreadName=a run exceptionTime=1496548324664Exception in thread "a" java.lang.NumberFormatException: For input string: "a"    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)    at java.lang.Integer.parseInt(Integer.java:580)    at java.lang.Integer.parseInt(Integer.java:615)    at com.qbian.thread.Object01.testMethod(Object01.java:14)    at com.qbian.thread.ThreadC.run(ThreadC.java:13)Thread B run Time=1496548324965

可以看到,在线程名为a执行时出现异常后,会立马将其持有的object 对象的锁释放掉,线程名为b的会立马获得object 对象的锁,继续执行b自身的任务。

同步不具有继承性

即父类的某个方法被synchronized修饰,但子类重写了父类的该方法后没有使用synchronized关键字修饰该方法。当多线程调用子类的该方法时是非同步调用的。要想使子类的该方法也具有同步性就需要在子类重写后的该方法前再次加上synchronized关键字修饰。