5.synchronized代码块。

本文深入探讨了Java中synchronized关键字的使用技巧与注意事项,包括如何通过synchronized代码块优化线程执行效率,不同类型的锁(对象锁、类锁、任意对象锁)的应用场景及其区别,以及如何避免死锁等问题。
  1. 使用synchronized声明的方法在某些情况下是有弊端的,比如:当A线程调用同步的方法执行一个长时间的任务,那么B线程就需要等待较长的时间才能执行,这样情况下可以使用synchronized代码块去优化代码的执行时间,减小锁的粒度。
  2. public class Optimize {
  3.  
  4.    public void doLongTimeTask(){
  5.       try {
  6.         
  7.          System.out.println("当前线程开始:" + Thread.currentThread().getName() +
  8.                 ", 正在执行一个较长时间的业务操作,其内容不需要同步");
  9.          Thread.sleep(2000);
  10.          同步代码块
  11.          synchronized(this){
  12.             System.out.println("当前线程:" + Thread.currentThread().getName() +
  13.                 ", 执行同步代码块,对其同步变量进行操作");
  14.             Thread.sleep(1000);
  15.          }
  16.          System.out.println("当前线程结束:" + Thread.currentThread().getName() +
  17.                 ", 执行完毕");
  18.         
  19.       } catch (InterruptedException e) {
  20.          e.printStackTrace();
  21.       }
  22.    }
  23.   
  24.    public static void main(String[] args) {
  25.       final Optimize otz = new Optimize();
  26.       Thread t1 = new Thread(new Runnable() {
  27.          @Override
  28.          public void run() {
  29.             otz.doLongTimeTask();
  30.          }
  31.       },"t1");
  32.       Thread t2 = new Thread(new Runnable() {
  33.          @Override
  34.          public void run() {
  35.             otz.doLongTimeTask();
  36.          }
  37.       },"t2");
  38.       t1.start();
  39.       t2.start();
  40.      
  41.    }
  42.   
  43.   
  44. }
  45. 输出结果:
  46. 当前线程开始:t1, 正在执行一个较长时间的业务操作,其内容不需要同步
  47. 当前线程开始:t2, 正在执行一个较长时间的业务操作,其内容不需要同步
  48. 当前线程:t2, 执行同步代码块,对其同步变量进行操作
  49. 当前线程:t1, 执行同步代码块,对其同步变量进行操作
  50. 当前线程结束:t1, 执行完毕
  51. 当前线程结束:t2, 执行完毕
  52.  
  53. Synchronized可以使用任意Object对象加锁,用法灵活。
  54. public class ObjectLock {
  55.  
  56.    public void method1(){
  57.       synchronized (this) { //对象锁
  58.          try {
  59.             System.out.println("do method1..");
  60.             Thread.sleep(2000);
  61.          } catch (InterruptedException e) {
  62.             e.printStackTrace();
  63.          }
  64.       }
  65.    }
  66.   
  67.    public void method2(){   //类锁
  68.       synchronized (ObjectLock.class) {
  69.          try {
  70.             System.out.println("do method2..");
  71.             Thread.sleep(2000);
  72.          } catch (InterruptedException e) {
  73.             e.printStackTrace();
  74.          }
  75.       }
  76.    }
  77.   
  78.    private Object lock = new Object();
  79.    public void method3(){   //任何对象锁
  80.       synchronized (lock) {
  81.          try {
  82.             System.out.println("do method3..");
  83.             Thread.sleep(2000);
  84.          } catch (InterruptedException e) {
  85.             e.printStackTrace();
  86.          }
  87.       }
  88.    }
  89.   
  90.   
  91.    public static void main(String[] args) {
  92.      
  93.       final ObjectLock objLock = new ObjectLock();
  94.       Thread t1 = new Thread(new Runnable() {
  95.          @Override
  96.          public void run() {
  97.             objLock.method1();
  98.          }
  99.       });
  100.       Thread t2 = new Thread(new Runnable() {
  101.          @Override
  102.          public void run() {
  103.             objLock.method2();
  104.          }
  105.       });
  106.       Thread t3 = new Thread(new Runnable() {
  107.          @Override
  108.          public void run() {
  109.             objLock.method3();
  110.          }
  111.       });
  112.      
  113.       t1.start();
  114.       t2.start();
  115.       t3.start();
  116.      
  117.      
  118.    }
  119.   
  120. }
  121.  
  122. 输出结果:
  123. do method1..
  124. do method3..
  125. do method2..
  126.  
  127. Synchronized不能使用String的常量池加锁,会出现死循环。
  128. public class StringLock {
  129.  
  130.    public void method() {
  131.       // String s = new String("字符串常量")用不会出现死循环
  132.       synchronized ("字符串常量") {
  133.          try {
  134.             while(true){
  135.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
  136.                 Thread.sleep(1000);  
  137.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
  138.             }
  139.          } catch (InterruptedException e) {
  140.             e.printStackTrace();
  141.          }
  142.       }
  143.    }
  144.   
  145.    public static void main(String[] args) {
  146.       final StringLock stringLock = new StringLock();
  147.       Thread t1 = new Thread(new Runnable() {
  148.          @Override
  149.          public void run() {
  150.             stringLock.method();
  151.          }
  152.       },"t1");
  153.       Thread t2 = new Thread(new Runnable() {
  154.          @Override
  155.          public void run() {
  156.             stringLock.method();
  157.          }
  158.       },"t2");
  159.      
  160.       t1.start();
  161.       t2.start();
  162.    }
  163. }
  164. 输出结果:
  165. 当前线程 : t2开始
  166. 当前线程 : t2结束
  167. 当前线程 : t2开始
  168. 当前线程 : t2结束
  169. 当前线程 : t2开始
  170. 当前线程 : t2结束
  171. 当前线程 : t2开始
  172. 当前线程 : t2结束
  173. ……………………
  174. 死循环。
  175.  
  176.  
  177. 锁对象的改变,当使用一个对象进行加锁的时候,对象本身发生改变,持有的锁就是不同的,如果对象本身不改变,那么依然是同步的,即使对象的属性发生了改变。
  178. public class ModifyLock {
  179.   
  180.    private String name ;
  181.    private int age ;
  182.   
  183.    public String getName() {
  184.       return name;
  185.    }
  186.    public void setName(String name) {
  187.       this.name = name;
  188.    }
  189.    public int getAge() {
  190.       return age;
  191.    }
  192.    public void setAge(int age) {
  193.       this.age = age;
  194.    }
  195.   
  196.    public synchronized void changeAttributte(String name, int age) {
  197.       try {
  198.          System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 开始");
  199.          this.setName(name);
  200.          this.setAge(age);
  201.         
  202.          System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 修改对象内容为: "
  203.                 + this.getName() + ", " + this.getAge());
  204.         
  205.          Thread.sleep(2000);
  206.          System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 结束");
  207.       } catch (InterruptedException e) {
  208.          e.printStackTrace();
  209.       }
  210.    }
  211.   
  212.    public static void main(String[] args) {
  213.       final ModifyLock modifyLock = new ModifyLock();
  214.       final ModifyLock modifyLock1 = new ModifyLock();
  215.       Thread t1 = new Thread(new Runnable() {
  216.          @Override
  217.          public void run() {
  218.             modifyLock.changeAttributte("张三", 20);
  219.          }
  220.       },"t1");
  221.       Thread t2 = new Thread(new Runnable() {
  222.          @Override
  223.          public void run() {
  224.             属性发生了改变
  225.             modifyLock.changeAttributte("李四", 21);
  226.          }
  227.       },"t2");
  228.      
  229.       t1.start();
  230.       try {
  231.          Thread.sleep(100);
  232.       } catch (InterruptedException e) {
  233.          e.printStackTrace();
  234.       }
  235.       t2.start();
  236.    }
  237.   
  238. }
  239.  
  240. 输出结果:结果还是同步的
  241. 当前线程 : t1 开始
  242. 当前线程 : t1 修改对象内容为: 张三, 20
  243. 当前线程 : t1 结束
  244. 当前线程 : t2 开始
  245. 当前线程 : t2 修改对象内容为: 李四, 21
  246. 当前线程 : t2 结束
  247.  
  248. 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况
  249. public class DeadLock implements Runnable{
  250.  
  251.    private String tag;
  252.    private static Object lock1 = new Object();
  253.    private static Object lock2 = new Object();
  254.   
  255.    public void setTag(String tag){
  256.       this.tag = tag;
  257.    }
  258.   
  259.    @Override
  260.    public void run() {
  261.       if(tag.equals("a")){
  262.          synchronized (lock1) {
  263.             try {
  264.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
  265.                 Thread.sleep(2000);
  266.             } catch (InterruptedException e) {
  267.                 e.printStackTrace();
  268.             }
  269.             synchronized (lock2) {
  270.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
  271.             }
  272.          }
  273.       }
  274.       if(tag.equals("b")){
  275.          synchronized (lock2) {
  276.             try {
  277.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
  278.                 Thread.sleep(2000);
  279.             } catch (InterruptedException e) {
  280.                 e.printStackTrace();
  281.             }
  282.             synchronized (lock1) {
  283.                 System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
  284.             }
  285.          }
  286.       }
  287.    }
  288.   
  289.    public static void main(String[] args) {
  290.      
  291.       DeadLock d1 = new DeadLock();
  292.       d1.setTag("a");
  293.       DeadLock d2 = new DeadLock();
  294.       d2.setTag("b");
  295.        
  296.       Thread t1 = new Thread(d1, "t1");
  297.       Thread t2 = new Thread(d2, "t2");
  298.        
  299.       t1.start();
  300.       try {
  301.          Thread.sleep(500);
  302.       } catch (InterruptedException e) {
  303.          e.printStackTrace();
  304.       }
  305.       t2.start();
  306.    }
  307.   
  308.  
  309.   
  310. }
  311.  
  312. 输出结果:
  313. 当前线程 : t1 进入lock1执行
  314. 当前线程 : t2 进入lock2执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值