你的位置:首页 > Java教程

[Java教程]Java synchronized同步 各方式略解


  近段为了实现一个功能,在树结构中,修改某个节点名称时,需要同时修改这个节点所有子节点的节点全路径属性字段(类似"父父节点名称/父节点名称/子节点名称/子子节点名称"的构造)。因为在构造Update语句时,需要递归去查询子节点以及构造全路径的值,需要花费了一定的时间,等批量执行update语句时,可能子节点的某个子节点的名称又改变了,会引起冲突,故用到了synchronized,顺便了解了下实现方式,原理没深入了解,在此记录以便日后查看。

-----------------------------------------------------我是正文分割线--------------------我是正文分割线---------------------------

本文主要列举不同的同步方式,以及我理解的使用范围。

众所周知,同步分为两种用法:同步方法、与同步块。

一、同步块

1.1 类同步(非静态方法)

· 实现方式:

 1 public class JustPlayServiceImplSyn2 { 2    3   public JustPlayServiceImplSyn2(){ 4      5   } 6   private static int flag = 1; 7   public void operate() {  8     synchronized(JustPlayServiceImplSyn2.class){ 9       flag++; 10       try { 11         // 增加随机性,让不同线程能在此交替执行 12         Thread.sleep(new Random().nextInt(5)); 13       } catch (InterruptedException e) { 14         e.printStackTrace(); 15       } 16       flag--; 17       System.out.println("Thread: " + Thread.currentThread().getName() 18           + " /Current flag: " + flag);19     }20   }21 }

View Code

· 测试代码:

 1 public class JustPlay { 2   /** 3    * @param args 4   */ 5   public static void main(String[] args) { 6        new Thread("Thread-01") {  7          public void run() {  8            new JustPlayServiceImplSyn2().operate(); 9           } 10        }.start(); // 启动第一个线程11        12     new Thread("Thread-02") { 13          public void run() { 14            new JustPlayServiceImplSyn2().operate();15           } 16        }.start(); // 启动第一个线程17   }18 }

View Code

· 使用范围:多对象多线程的同步。
  使用范围最广,代码也简单,在需要同步的代码块上加上synchronized关键字,并在括号类用[类名.class]就行。

1.2 this同步(非静态方法)

· 实现方式:

 1 public class JustPlayServiceImplSyn2 { 2    3   public JustPlayServiceImplSyn2(){ 4      5   } 6   private static int flag = 1; 7   public void operate_this() {  8     synchronized(this){ 9       flag++; 10       try { 11         // 增加随机性,让不同线程能在此交替执行 12         Thread.sleep(new Random().nextInt(5)); 13       } catch (InterruptedException e) { 14         e.printStackTrace(); 15       } 16       flag--; 17       System.out.println("Thread: " + Thread.currentThread().getName() 18           + " /Current flag: " + flag);19     }20   }21 }

View Code

· 测试代码:

 1 public class JustPlay { 2  3   /** 4    * @param args 5   */ 6   public static void main(String[] args) { 7     final JustPlayServiceImplSyn2 justplayserviceimplsyn2= new JustPlayServiceImplSyn2(); 8      for(int i=0;i<100;i++){ 9        new Thread("Thread-001"){10          public void run() {11             justplayserviceimplsyn2.operate_this();12           }13         }.start();14        new Thread("Thread-002"){15          public void run() {16             justplayserviceimplsyn2.operate_this();17           }18         }.start();19   }20 }

View Code

· 使用范围:单对象多线程的同步。

  在synchronized关键字后的括号内用this关键字。使用[this]同步时需要是同一对象的才能同步,多对象时是同步失败的。因为同步是对this对象锁,不同对象时锁互不影响

 

1.3 静态对象同步(非静态方法)

· 实现方式:

 1 public class JustPlayServiceImpl { 2   private static JustPlayServiceImpl myobj = null; 3    4   private JustPlayServiceImpl(){ 5      6   } 7   public static JustPlayServiceImpl createJustPlayServiceImpl(){ 8     if(myobj==null){ 9       myobj = new JustPlayServiceImpl();10     }11     return myobj;12   }13   private static int flag = 1;14   public void operate() { 15     synchronized(myobj){16       flag++; 17       try { 18         // 增加随机性,让不同线程能在此交替执行 19         Thread.sleep(new Random().nextInt(5)); 20       } catch (InterruptedException e) { 21         e.printStackTrace(); 22       } 23       flag--; 24       System.out.println("Thread: " + Thread.currentThread().getName() 25           + " /Current flag: " + flag);26     }27   }28 }

View Code

· 测试代码:

 1 public class JustPlay { 2 3   /** 4   * @param args 5   */ 6   public static void main(String[] args) { 7 8      for(int i=0;i<100;i++){ 9        new Thread("Thread-01") { 10          public void run() { 11            JustPlayServiceImpl.createJustPlayServiceImpl().operate())          } 12        }.start(); // 启动第一个线程13      new Thread("Thread-02") { 14          public void run() { 15            JustPlayServiceImpl.createJustPlayServiceImpl().operate()          } 16        }.start(); // 启动第二个线程17      }

View Code

· 使用范围:单体类单对象多线程的同步。

  因为同步是对对象的同步锁,只要保证同步块对象唯一,就能实现同步。偷点懒,我直接将类变成了单体类,然后将唯一对象给锁了。(ps:怎么感觉有点鬼畜。。。哈哈哈)

二、同步方法

2.1 静态方法同步

· 实现方式:

 1 public class JustPlayServiceImplSyn2 { 2    3   public JustPlayServiceImplSyn2(){ 4      5   } 6   private static int flag = 1; 7   public synchronized static void operate_static(){ 8     flag++;  9     try { 10       // 增加随机性,让不同线程能在此交替执行 11       Thread.sleep(new Random().nextInt(5)); 12     } catch (InterruptedException e) { 13       e.printStackTrace(); 14     } 15     flag--; 16     System.out.println("Thread: " + Thread.currentThread().getName() 17         + " /Current flag: " + flag);18   }19 }

View Code

· 测试代码:

 1 public class JustPlay { 2  3   /** 4    * @param args 5   */ 6   public static void main(String[] args) { 7      for(int i=0;i<100;i++){ 8        new Thread("Thread-01") {  9          public void run() { 10             JustPlayServiceImplSyn2.operate_static();11           } 12        }.start(); // 启动第一个线程13        14     new Thread("Thread-02") { 15          public void run() { 16             JustPlayServiceImplSyn2.operate_static();17           } 18        }.start(); // 启动第一个线程19     }20   }21 }

View Code

· 使用范围:静态方法单对象多线程的同步。

  再次说[因为同步是对对象的同步锁],而且调用静态方法绑定的是类而不是对象,所以,同步了静态方法,就是将相当于将类给锁了,然后就同步了。原理与[1.1 类同步(非静态方法)]一致。

2.2 非静态方法同步

  2.2.1 单体类非静态方法同步

  ·  实现方式:  

 1 public class JustPlayServiceImpl { 2   private static JustPlayServiceImpl myobj = null; 3    4   private JustPlayServiceImpl(){ 5      6   } 7   public static JustPlayServiceImpl createJustPlayServiceImpl(){ 8     if(myobj==null){ 9       myobj = new JustPlayServiceImpl();10     }11     return myobj;12   }13   private static int flag = 1;14   15   //单体类 此种同步方式有效16   public synchronized void operate2() { 17       flag++; 18       try { 19         // 增加随机性,让不同线程能在此交替执行 20         Thread.sleep(new Random().nextInt(5)); 21       } catch (InterruptedException e) { 22         e.printStackTrace(); 23       } 24       flag--; 25       System.out.println("Thread: " + Thread.currentThread().getName() 26           + " /Current flag: " + flag);27   }28 }

View Code

  · 测试代码:

 1   public static void main(String[] args) { 2  3      for(int i=0;i<100;i++){ 4        new Thread("Thread-01") {  5          public void run() {  6             JustPlayServiceImpl.createJustPlayServiceImpl().operate2(); 7           }  8        }.start(); // 启动第一个线程 9        10      new Thread("Thread-02") { 11          public void run() { 12            JustPlayServiceImpl.createJustPlayServiceImpl().operate2();13           } 14        }.start(); // 启动第一个线程15       }16     }17 }

View Code

  · 使用范围:单体类单对象多线程的同步。

    原理同[1.3 静态对象同步(非静态方法)]

  2.2.2 非单体类非静态方法同步

  · 实现方式:

 1 public class JustPlayServiceImplSyn2 { 2    3   public JustPlayServiceImplSyn2(){ 4      5   } 6   private static int flag = 1; 7   //适用于单对象多线程 8   public synchronized void operate2() {  9       flag++; 10       try { 11         // 增加随机性,让不同线程能在此交替执行 12         Thread.sleep(new Random().nextInt(5)); 13       } catch (InterruptedException e) { 14         e.printStackTrace(); 15       } 16       flag--; 17       System.out.println("Thread: " + Thread.currentThread().getName() 18           + " /Current flag: " + flag);19   }20 }

View Code

  · 测试代码:

 1 public class JustPlay { 2  3   /** 4    * @param args 5   */ 6   public static void main(String[] args) { 7     final JustPlayServiceImplSyn2 justplayserviceimplsyn2= new JustPlayServiceImplSyn2(); 8      for(int i=0;i<100;i++){ 9        new Thread("Thread-001"){10          public void run() {11             justplayserviceimplsyn2.operate2();12           }13         }.start();14        new Thread("Thread-002"){15          public void run() {16             justplayserviceimplsyn2.operate2();17           }18         }.start();19     }20 }

View Code

  · 使用范围:单对象多线程的同步。

    原理同[1.2 this同步(非静态方法)]

总结:对于网页用ajax方式多次调用的class,因为是多线程且不可控为单一对象,若想同步:解决方案是:1.1、1.3、2.1、2.2.1;对于1.2和2.2.2,调用的对象必须是保持同一个才会同步。

PS:觉得应该还有其他方式,隐隐的这么觉得。。。。。哈哈哈哈哈哈

------------------------------------结束的分割线--------------结束的分割线------------------有机会再去了解同步的底层原理去了----那时候再写原理------またね!---