最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

架构系列——使用synchronized需要注意什么细节

XAMPP案例 admin 125浏览 0评论

前言

synchronized可以为任意对象加锁,用法比较灵活,语法如下

(1)修饰代码块,作用于调用的对象;

(2)修饰方法,作用于调用的对象;

(3)修饰静态方法,作用于所有对象;

(4)修饰类,作用于所有对象。

synchronized取得的锁都是对象锁,而不是把一段代码(或者方法)当成锁!

使用synchronized时,应该注意以下细节问题:01synchronized锁的重入性

如下列代码所示,类似于ReentrantLock

在method1中没有释放锁的情况下,可以继续调用synchronized修饰的method2

public class SyncDubbo {
  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("method1...");
  }
  

  public static void main(String[] args) {
    final SyncDubbo sd = new SyncDubbo();
    Thread t1 = new Thread(new Runnable(){
      @Override
      public void run() {
        // TODO Auto-generated method stub
        sd.method1();
      }
      

    }, "t1");
    t1.start();
  }
}

如下列代码所示,在子类与父类之间相互调用也运用了synchronized的重用性

public class FatherSon {
  static class Father {
    public int num = 10;
    public synchronized void method1(){
      try {
        num --;
        System.out.println("Father num = " + num);
        Thread.sleep(100);
      } catch (Exception e) {
        // TODO: handle exception
      }
    }
  }
  

  static class Son extends Father {
    public synchronized void method2(){
      try {
        while (num >0) {
          num --;
          System.out.println("Son num = " + num);
          Thread.sleep(100);
          this.method1();
        }
      } catch (Exception e) {
        // TODO: handle exception
      }
    }
  }
  public static void main(String[] args) {
    Thread t1 = new Thread(new Runnable(){
      @Override
      public void run() {
        // TODO Auto-generated method stub
        Son son = new Son();
        son.method2();
      }
    }, "t1");
    t1.start();
  }
}

02不要使用字符串常量作为锁

如下列代码所示,使用了字符串常量作为锁,那么t1和t2运行之后将会一直在t1中出现死循环,t2永远拿不到锁!

解决:可以使用 new String(“字符串常量”) 作为锁

public class StringLock {
  public void method(){
    synchronized("字符串常量"){
      try {
        while (true){
          System.out.println("当前线程:" + Thread.currentThread().getName() + "开始");
          Thread.sleep(1000);
          System.out.println("当前线程:" + Thread.currentThread().getName() + "结束");
        }
      } catch (Exception e) {
        // TODO: handle exception
      }
    }
  }
  

  public static void main(String[] args) {
    final StringLock sl = new StringLock();
    Thread t1 = new Thread(new Runnable() {
      @Override
      public void run() {
        // TODO Auto-generated method stub
        sl.method();
      }
      

    }, "t1");
    Thread t2 = new Thread(new Runnable() {
      @Override
      public void run() {
        // TODO Auto-generated method stub
        sl.method();
      }
      

    }, "t2");
    t1.start();
    t2.start();
  }
}

03锁对象的改变问题

如下列代码所示,使用synchronized锁住了一个对象,并且在代码里重新new了一个对象,导致锁对象改变。

这样在t1还没有运行完代码的时候,t2就已经可以拿到锁了,显然会出现问题!

解决:不要改变锁对象(但是改变对象的属性对代码不会有影响,比如锁是一个人,那么可以改变这个人的身高、年龄等)

public class ChangeLock {
  Object obj = new Object();
  

  public void method(){
    synchronized(obj){
      try {
        System.out.println("当前线程:" + Thread.currentThread().getName() + "开始");
        //从这里改变锁对象
        obj = new Object();
        Thread.sleep(3000);
        System.out.println("当前线程:" + Thread.currentThread().getName() + "结束");
      } catch (Exception e) {
        // TODO: handle exception
      }
    }
  }
  public static void main(String[] args) {
    final ChangeLock cl = new ChangeLock();
    Thread t1 = new Thread(new Runnable() {
      @Override
      public void run() {
        // TODO Auto-generated method stub
        cl.method();
      }
      

    }, "t1");
    Thread t2 = new Thread(new Runnable() {
      @Override
      public void run() {
        // TODO Auto-generated method stub
        cl.method();
      }
      

    }, "t2");
    t1.start();
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    t2.start();
  }
}

转载请注明:XAMPP中文组官网 » 架构系列——使用synchronized需要注意什么细节

您必须 登录 才能发表评论!