问题1:子类可以调用父类的同步方法吗?
/** * * 一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁, * 再次申请时,仍然会得到该对象的锁,也就是说synchronized获得的锁是可重入的 * * 这里是继承中有可能发生的情形,子类调用父类的同步方法 */public class Test09 { synchronized void a(){ System.out.println("a....start.."); } public static void main(String[] args) { T t = new T(); t.b(); } static class T extends Test09{ synchronized void b(){ System.out.println("b...start..."); super.a(); } }}
运行结果是:
问题2:程序在执行过程中,如果出现异常,锁会怎么样?
/** * 程序在执行过程中,如果出现异常,默认情况锁会被释放 * 所以,在并发处理过程中,有异常要多加小心,不然可能会发生不一致的情况, * 比如在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时,如果异常处理不合适 * 在第一个线程中抛出异常,其他线程就会进入同步代码区,有可能会访问到异常产生时的数据 * 因此要非常小心的处理同步业务逻辑中的异常 */public class Test10 { int count = 0; synchronized void m1() { System.out.println(Thread.currentThread().getName() + " start...."); while(true){ count ++; System.out.println(Thread.currentThread().getName() + " start...." + count); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if(count == 5) { int a = count / 0; try { }catch (Exception e){ } } } } public static void main(String[] args) { Test10 test10 = new Test10(); new Thread(new Runnable() { @Override public void run() { test10.m1(); } }).start(); new Thread(new Runnable() { @Override public void run() { test10.m1(); } }).start(); }}
运行结果:
问题3:如下程序执行的结果是?
/** * 锁定某对象o,如果o的属性发生改变,不影响锁的使用 * 但是如果o变成另外一个对象,则锁定的对象发生改变 * 应该避免将锁定的对象变成另外一个对象 */public class Test { Object o = new Object(); void m() { synchronized (o){ while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } } public static void main(String[] args) { Test test = new Test(); new Thread(new Runnable() { @Override public void run() { test.m(); } },"jjj").start(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } test.o = new Object(); // 锁对象发生改变,所以t2线程得以执行,如果注释掉这句话,线程2将永远得不到执行 new Thread(new Runnable() { @Override public void run() { test.m(); } },"ddddd").start(); }}
执行结果是:
问题4:编程经验
/** * 不要以字符串常量作为锁定对象 * 在下面的例子中,m1和m2其实锁定的是一个对象 * 这种情况还会发生比较诡异的现象,比如你用到一个类库,在该类库中代码锁定了字符串常量“Hello”, * 但是你读不到源码,所以你在自己的代码中也锁定了“Hello”,这时候就可能发生非常诡异的死锁阻塞, * 因为你的程序和你用到的类库不经意间使用了同一把锁 * * jetty */public class Test { String h1 = "Hello"; String h2 = "Hello"; void m1 (){ synchronized (h1){ } } void m2() { synchronized (h2){ } } public static void main(String[] args) { }
本文分享自微信公众号 - Java学习进阶手册(javastudyup)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。