synchronized 方法 导致插入数据插不进_架构系列——使用synchronized需要注意什么细节...

a4f5d70aaafe1c07e954cc493905b5e4.gif点击上方“蓝字”带你去看小星星 0bc574528df0d3192c55b52e46ec584b.png ddbd52f9a727021a6ddf1874678fa777.png前言

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

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

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

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

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

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

使用synchronized时,应该注意以下细节问题:

0 1synchronized锁的重入性

如下列代码所示,类似于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();  }}

5561939e743d1ab58025e875be9aa176.gif

● 架构系列——线程实现方式以及生命周期的探索

● 架构系列——并发、并行与多线程关系探索

● 架构系列——单体、分布式、集群与冗余的探索

● Java反射:框架设计的灵魂

● 高并发秒杀系统如何设计与优化

● 要准备多少东西去面试---java中高级面试总结(值得收藏)

● 最近的面试有感(7个方面)

● 常用数据结构及其Java实现

● java中的参数传递(只有值传递没有引用传递)

● 38张史上最全的IT工程师技能图谱(高清收藏)

● PLSQL连接本地oracle或远程oracle数据库,实现随意切换(送福利)

● 通过数据泵expdp、impdp方式备份与还原Oracle数据库--值得收藏

● java常见排序算法--选择排序、冒泡排序、插入排序分析与比较

4c36a54bf29630ea0cb3c3eb07079810.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值