zoukankan      html  css  js  c++  java
  • synchronized细节问题(一)

    synchronized锁重入:

      关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。

    下面看一段锁重入的小demo:

    public class SyncDubbo1 {
    public synchronized void method1() {
    System.out.println("method1..");
    method2();
    }

    public synchronized void method2() {
    System.out.println("method2..");
    method3();
    }

    public synchronized void method3() {
    System.out.println("method3..");
    }

    public static void main(String[] args) {
    final SyncDubbo1 sd = new SyncDubbo1();
    Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
    sd.method1();
    }
    });
    t1.start();
    }
    }

    这中方式的调用是没有任何问题的,运行的结果是

    method1..
    method2..
    method3..

    这是一个最简单的锁重入的问题,是完全没有任何问题的。

    下面看一个稍微复杂点的锁重入的代码:

    public class SyncDubbo2 {
    static class Main {
    public int i = 10;

    private synchronized void operationSup() {
    try {
    i--;
    System.out.println("Main print i = " + i);
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    static class Sub extends Main {
    public synchronized void operationSub() {
    try {
    while (i > 0) {
    i--;
    System.out.println("Sub print i = " + i);
    Thread.sleep(100);
    this.operationSub();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    public static void main(String[] args) {
    Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
    Sub sub = new Sub();
    sub.operationSub();
    }
    });
    }
    }

    运行结果是:

    Sub print i = 9
    Main print i = 8
    Sub print i = 7
    Main print i = 6
    Sub print i = 5
    Main print i = 4
    Sub print i = 3
    Main print i = 2
    Sub print i = 1
    Main print i = 0

    这个结果是没有任何问题的,通过这个例子是想说明,再有父子继承关系的时候,然后都加synchronized修饰时,这样去调用也是线程安全的。这是对于synchronized应用的第二种形式。

    下面在看一个synchronized中修饰的方法里面,碰到某些异常时,出现的情况,下面也看一个demo;

    public class SyncException {
    private int i = 0;

    public synchronized void operation() {
    while (true) {
    try {
    i++;
    Thread.sleep(200);
    System.out.println(Thread.currentThread().getName() + " ,i = " + i);
    if (i == 5) {
    Integer.parseInt("a");
    }
    } catch (Exception e) {
    e.printStackTrace();
    System.out.println(" log info i = " + i);
    }
    }
    }

    public static void main(String[] args) {
    final SyncException se = new SyncException();
    Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
    se.operation();
    }
    },"t1");
    t1.start();
    }
    }

    这段代码在i=5的时候代码发生异常,这种情况下,synchronized会自动解锁,程序会继续执行,发生异常的情况下,我们一定要对异常情况进行处理,运行的结果是:

    t1 ,i = 1
    t1 ,i = 2
    t1 ,i = 3
    t1 ,i = 4
    t1 ,i = 5
    log info i = 5
    java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at Thread.SyncException.operation(SyncException.java:16)
    at Thread.SyncException$1.run(SyncException.java:31)
    at java.lang.Thread.run(Thread.java:744)
    t1 ,i = 6
    t1 ,i = 7
    t1 ,i = 8

    在实际开发中,对 这种异常有两种方式的处理,第一种就是上面写的这种,catch到异常后,把对应的数据记录到日志,当然有个前提条件,就是每次去执行这个任务之间都是没有关联的;还有一种情况,执行的任务是有关联的,是一个整体,假如采用前面那种情况,在异常发生后的几次情况的执行都是有问题的,这也有一个解决方法,就是补或一个打断异常,InterruptedException,或者抛出一个运行时异常,就能停止这个线程。

    总结:对于web应用程序,异常释放锁的情况,如果不及时处理,很可能对你的应用程序业务逻辑产生严重的错误,比如你现在执行一个队列任务,很多对象都去在等待第一个对象正确执行完毕再去释放锁,但是第一个对象由于异常的出现,导致业务逻辑没有正常执行完毕,就释放了锁,那么可想而知后续的对象执行的都是错误的逻辑。所以这一点一定要引起注意,在编写代码的时候,一定要考虑周全。

  • 相关阅读:
    大规模分布式存储系统笔记一二章 概述与单机存储系统
    Apache Avro总结
    可汗学院公开课统计学笔记 第11到16集 样本 总体 方差 标准差 诸方差公式
    可汗学院公开课统计学笔记 第1到10集 均值 中位数 众数 极差 统计图
    Mock、Powermock使用汇总
    如何解决NoSuchMethodError
    2019年我看手机之华为篇
    活着
    log4j使用指北
    关于Eclipse导入maven项目报空指针异常
  • 原文地址:https://www.cnblogs.com/shmilyToHu/p/6386112.html
Copyright © 2011-2022 走看看