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:觉得应该还有其他方式,隐隐的这么觉得。。。。。哈哈哈哈哈哈

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

 

posted @ 2015-10-30 12:30  编程王小宇  阅读(313)  评论(0编辑  收藏  举报