一起看看ynchronized的4个特性

2025-04-28 16:45:04 6
  • 收藏
  • 管理
    1. synchronized锁重入 1.1 介绍 关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。这说明在一个synchronized方法/块内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。 例如: 复制publicclassService1{publicsynchronizedvoid method1(){System.out.println("method1"); method2();}publicsynchronizedvoid method2(){System.out.println("method2"); method3();}publicsynchronizedvoid method3(){System.out.println("method3");}} 复制publicclassMyThreadextendsThread{@Overridepublicvoid run(){Service1 service1 =newService1(); service1.method1();}publicstaticvoid main(String[] args){MyThread myThread =newMyThread(); myThread.start();}} 运行结果如下: ? 看到这个结果的时候是茫然了,怎么就证明是可重入锁的了呢? ? “可重入锁”的概念是:自己可以再次获取自己的内部锁,比如有1个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。 ? “可重入锁”的最大作用就是避免死锁 1.2 分析 我们知道,在程序中,是无法显式释放对同步监视器的锁的,而会在如下几个情况下释放锁: ① 当前线程的同步方法、代码块执行结束的时候释放 ② 当前线程在同步方法、同步代码块遇到break、return终止该代码块或方法的时候释放 ③ 出现未处理的error或exception导致异常结束的时候释放 ④ 程序执行了同步对象wait方法,当前线程暂停,释放锁 那么,在上面的程序中,当线程进入同步方法method1时获得Service1的对象锁,但是在执行method1的时候调用了同步方法method2,按照正常情况,在执行同步方法method2同样需要获得对象锁,但是根据上面释放锁的条件,此时method1的对象锁还没有释放,此时就会造成死锁,无法继续执行method2。但是通过上面代码的执行结果来看,能够正常执行method2和method3,这就说明,在一个Synchronized修饰的方法或代码块的内部调用本类的其他Synchronized修饰的方法或代码块时,是永远可以得到锁的。 1.3 父子可继承性 可重入锁支持在父子类继承的环境中,示例代码如下: 复制publicclassService2{publicint i =10;publicsynchronizedvoid mainMethod(){ i--;System.out.println("main print i=" i);try{Thread.sleep(100);}catch(InterruptedException e){ e.printStackTrace();}}} 复制publicclassService3extendsService2{publicsynchronizedvoid subMethod(){try{while(i>0){ i--;System.out.println("sub print i= " i);Thread.sleep(100);this.mainMethod();}}catch(InterruptedException e){ e.printStackTrace();}}} 复制publicclassMyThreadextendsThread{@Overridepublicvoid run(){Service3 service3 =newService3(); service3.subMethod();}publicstaticvoid main(String[] args){MyThread myThread =newMyThread(); myThread.start();}} 运行结果如下: 此程序说明,当存在父子类继承关系时,子类完全可以通过“可重入锁”调用父类的同步方法。 2. 出现异常,锁自动释放 当一个线程执行的代码出现异常时,其所持有的锁会自动释放。 验证代码如下: 复制publicclassService4{publicsynchronizedvoid testMethod(){if(Thread.currentThread().getName().equals("a")){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());}}} 复制publicclassThreadAextendsThread{privateService4 service4;publicThreadA(Service4 service4){this.service4 = service4;}@Overridepublicvoid run(){ service4.testMethod();}} 复制publicclassThreadBextendsThread{privateService4 service4;publicThreadB(Service4 service4){this.service4 = service4;}@Overridepublicvoid run(){ service4.testMethod();}} 复制publicclassMain{publicstaticvoid main(String[] args){try{Service4 service4 =newService4();ThreadA a =newThreadA(service4); a.setName("a"); a.start();Thread.sleep(500);ThreadB b =newThreadB(service4); b.setName("b"); b.start();}catch(InterruptedException e){ e.printStackTrace();}}} 注意Service4类中Integer.parseInt(“a”);此时处于被注释状态,运行结果如下: 由于a线程没有错误,while(true),此时a线程处于无限循环状态,锁一直被a占用,b线程无法获得锁,即无法执行b线程。 将Service4类中Integer.parseInt(“a”);解开注释,执行的结果如下: 当a线程发生错误时,b线程获得锁从而执行,由此可见,当方法出现异常时,锁自动释放。 3. 将任意对象作为监视器 java支持对“任意对象”作为“对象监视器”来实现同步的功能。这个“任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象x)同步代码块。 示例代码如下: 复制publicclassStringLock{privateStringlock="lock";publicvoid method(){synchronized(lock){try{System.out.println("当前线程: "Thread.currentThread().getName()"开始");Thread.sleep(1000);System.out.println("当前线程: "Thread.currentThread().getName()"结束");}catch(InterruptedException e){ e.printStackTrace();}}}publicstaticvoid main(String[] args){finalStringLock stringLock =newStringLock();newThread(newRunnable(){@Overridepublicvoid run(){ stringLock.method();}},"t1").start();newThread(newRunnable(){@Overridepublicvoid run(){ stringLock.method();}},"t2").start();}} 运行结果如下: 锁非this对象具有一定的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不予其他锁this同步方法争抢this锁,则可大大提高运行效率。 4. 同步不具有继承性 父类的同步方法,在子类中重写后不加同步关键字,是不会同步的,所以还得在子类的方法中添加synchronized关键字。 推荐学习:Java视频教程
    上一页:一起看看百度快照的网络运营 下一页:一起看看pythonpygame简单画板实现代码实例
    全部评论(0)