• java同步和互斥【用具体程序说明】


    java同步和互斥【用具体程序说明】

     
             所有对象都自动含有单一的锁,也就是所有对象都有且只有唯一的锁,所以当某个任务(线程)访问一个类A中含有sycnhronized的方法是,那么在这个线程从该方法返回之前(也就是该方法在当前线程执行完之前),类A中的其他被该关键字标记的方法在其他的线程中都会被阻塞。
                通俗点说就是,当调用A的含有synchronized的方法是,A会被枷锁,此时A中其他含有synchronized方法只有等到前一个方法调用完毕释放了锁才能被调用

               具体说明见另一篇博客<<java同步和互斥【相关原理】》

            下面看看具体的程序,其中,Timer中的字段num是共享资源

    [java] view plain copy
     
    1. package com.bankht.synchronize;  
    2.   
    3. public class TestSync implements Runnable {  
    4.     Timer timer = new Timer();  
    5.   
    6.     public static void main(String[] args) {  
    7.         TestSync test = new TestSync();  
    8.         Thread t1 = new Thread(test);  
    9.         Thread t2 = new Thread(test);  
    10.         t1.setName("t1");  
    11.         t2.setName("t2");  
    12.         t1.start();  
    13.         t2.start();  
    14.     }  
    15.   
    16.     public void run() {  
    17.         timer.add(Thread.currentThread().getName());  
    18.     }  
    19. }  
    20.   
    21. class Timer {  
    22.     private static int num = 0;  
    23.   
    24.     public void add(String name) {  
    25.   
    26.         num++;  
    27.         try {  
    28.             Thread.sleep(1);  
    29.         } catch (InterruptedException e) {  
    30.         }  
    31.         System.out.println(name + ", 你是第" + num + "个使用timer的线程");  
    32.   
    33.     }  
    34. }  


     

    [java] view plain copy
     
    1. 由于没有同步,所以运行结果如下所示   

    t1, 你是第2个使用timer的线程

    t2, 你是第2个使用timer的线程

    也就是说当线程一运行到num++的时候被打线程2打断了,由于java中递增和递减操作均不是原子操作,所以本程序中即使没有调用sleep,也会出现这种被打断的情况

    下面看看同步的效果

    [java] view plain copy
     
    1. public void add(String name) {  
    2.        synchronized (this) {//同步  
    3.            num++;  
    4.            try {  
    5.                Thread.sleep(1000);  
    6.            } catch (InterruptedException e) {  
    7.            }  
    8.            System.out.println(name + ", 你是第" + num + "个使用timer的线程");  
    9.        }  
    10.    }  


    这样运行结果就会出是正确的

    t1, 你是第1个使用timer的线程

    t2, 你是第2个使用timer的线程

    但是,下面为了说明问题把TestSync里面的run方法改成如下所示

    [java] view plain copy
     
    1. public void run() {  
    2. /         
    3.            time.add(Thread.currentThread().getName());  
    4.            try {  
    5.                Thread.sleep(1000);//为了显示结果,让其睡眠一秒  
    6.            } catch (InterruptedException ex) {  
    7.                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
    8.            }  
    9.          System.out.println(Thread.currentThread().getName() + "----");  
    10.        }  


     

    那么在此运行就是

    t1, 你是第1个使用timer的线程

    t2, 你是第2个使用timer的线程

    t1--------

    t2--------

    而不是你所想象的

    t1, 你是第1个使用timer的线程
    t1----
    t2, 你是第2个使用timer的线程
    t2----

    原因就是在线程t1在睡眠的时候,线程t2切换进来,执行了一次,怎样得到正确的结果呢,下面把TestSync里面的run方法做如下改进就可以得到上面预期的结果

    [java] view plain copy
     
    1. public void run() {  
    2.       synchronized(time){  
    3.            time.add(Thread.currentThread().getName());  
    4.            try {  
    5.                Thread.sleep(3000);  
    6.            } catch (InterruptedException ex) {  
    7.                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
    8.            }  
    9.          System.out.println(Thread.currentThread().getName() + "----");  
    10.        }  
    11.    }  


    因为t1先获得time的锁,所以在执行完run里面的同步块之前,即使sleep(),t2也不会执行,因为t2没有获得time的锁,且sleep()操作也不释放锁(这也是和wait的巨大区别)

    附录:TestSync.java全部代码

    [java] view plain copy
     
    1. package com.bankht.synchronize;  
    2.   
    3. import java.util.logging.Level;  
    4. import java.util.logging.Logger;  
    5.   
    6. public class TestSync implements Runnable {  
    7.     Timer timer = new Timer();  
    8.   
    9.     public static void main(String[] args) {  
    10.         TestSync test = new TestSync();  
    11.         Thread t1 = new Thread(test);  
    12.         Thread t2 = new Thread(test);  
    13.         t1.setName("t1");  
    14.         t2.setName("t2");  
    15.         t1.start();  
    16.         t2.start();  
    17.     }  
    18.   
    19. //  public void run() {  
    20. //      timer.add(Thread.currentThread().getName());  
    21. //  }  
    22.       
    23. //   public void run() {  
    24. //       timer.add(Thread.currentThread().getName());  
    25. //            try {  
    26. //                Thread.sleep(1000);//为了显示结果,让其睡眠一秒  
    27. //            } catch (InterruptedException ex) {  
    28. //                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
    29. //            }  
    30. //          System.out.println(Thread.currentThread().getName() + "----");  
    31. //        }  
    32.       
    33.      public void run() {  
    34.            synchronized(timer){  
    35.                 timer.add(Thread.currentThread().getName());  
    36.                 try {  
    37.                     Thread.sleep(3000);  
    38.                 } catch (InterruptedException ex) {  
    39.                     Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
    40.                 }  
    41.               System.out.println(Thread.currentThread().getName() + "----");  
    42.             }  
    43.         }  
    44. }  
    45.   
    46. class Timer {  
    47.     private static int num = 0;  
    48.   
    49. //  public void add(String name) {  
    50. //  
    51. //      num++;  
    52. //      try {  
    53. //          Thread.sleep(1000);  
    54. //      } catch (InterruptedException e) {  
    55. //      }  
    56. //      System.out.println(name + ", 你是第" + num + "个使用timer的线程");  
    57. //  
    58. //  }  
    59.       
    60.     public void add(String name) {  
    61.         synchronized (this) {// 同步  
    62.             num++;  
    63.             try {  
    64.                 Thread.sleep(1000);  
    65.             } catch (InterruptedException e) {  
    66.             }  
    67.             System.out.println(name + ", 你是第" + num + "个使用timer的线程");  
    68.         }  
    69.     }  
    70.       
    71.       
    72. }  


     

  • 相关阅读:
    随机验证码生成
    python之map和filter
    Json学习笔记
    动态规划求区间最值问题RMQ(Range Minimum/Maximum Query)
    积水问题
    5亿个数找中位数
    Linux下进程间通信:命名管道mkfifo
    Trie树总结
    树的公共祖先问题LCA
    类文件结构
  • 原文地址:https://www.cnblogs.com/du-0210/p/8431192.html
Copyright © 2020-2023  润新知