Java同步之synchronized

转载 2016年08月29日 17:25:37

from  http://blog.csdn.net/yongmi/article/details/8569886

Java中可以使用关键字synchronized进行线程同步控制,实现关键资源顺序访问,避免由于多线程并发执行导致的数据不一致性等问题。synchronized的原理是对象监视器(锁),只有获取到监视器的线程才能继续执行,否则线程会等待获取监视器。Java中每个对象或者类都有一把锁与之相关联,对于对象来说,监视的是这个对象的实例变量,对于类来说,监视的是类变量(一个类本身是类Class的对象,所以与类关联的锁也是对象锁)。synchronized关键字使用方式有两种:synchronized方法和synchronized块。这两种监视区域都和一个引入对象相关联,当到达这个监视区域时,JVM就会锁住这个引用对象,当离开时会释放这个引用对象上的锁(有异常退出时,JVM会释放锁)。对象锁是JVM内部机制,只需要编写同步方法或者同步块即可,操作监视区域时JVM会自动获取锁或者释放锁。

首先来看同步方法的例子:

[java] view plain copy
 print?
  1. public class SynchronizedTest1 extends Thread  
  2. {  
  3.     private synchronized void testSynchronizedMethod()  
  4.     {  
  5.         for (int i = 0; i < 10; i++)  
  6.         {  
  7.             System.out.println(Thread.currentThread().getName()  
  8.                     + " testSynchronizedMethod:" + i);  
  9.   
  10.             try  
  11.             {  
  12.                 Thread.sleep(100);  
  13.             }  
  14.             catch (InterruptedException e)  
  15.             {  
  16.                 e.printStackTrace();  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     @Override  
  22.     public void run()  
  23.     {  
  24.         testSynchronizedMethod();  
  25.     }  
  26.   
  27.     public static void main(String[] args)  
  28.     {  
  29.   
  30.                 SynchronizedTest1 t = new SynchronizedTest1();  
  31.         t.start();  
  32.         t.testSynchronizedMethod();  
  33.     }  
  34. }  
运行该程序输出结果为:

[java] view plain copy
 print?
  1. main testSynchronizedMethod:0  
  2. main testSynchronizedMethod:1  
  3. main testSynchronizedMethod:2  
  4. main testSynchronizedMethod:3  
  5. main testSynchronizedMethod:4  
  6. main testSynchronizedMethod:5  
  7. main testSynchronizedMethod:6  
  8. main testSynchronizedMethod:7  
  9. main testSynchronizedMethod:8  
  10. main testSynchronizedMethod:9  
  11. Thread-0 testSynchronizedMethod:0  
  12. Thread-0 testSynchronizedMethod:1  
  13. Thread-0 testSynchronizedMethod:2  
  14. Thread-0 testSynchronizedMethod:3  
  15. Thread-0 testSynchronizedMethod:4  
  16. Thread-0 testSynchronizedMethod:5  
  17. Thread-0 testSynchronizedMethod:6  
  18. Thread-0 testSynchronizedMethod:7  
  19. Thread-0 testSynchronizedMethod:8  
  20. Thread-0 testSynchronizedMethod:9  
可以看到testSynchronizedMethod方法在两个线程之间同步执行。

如果此时将main方法修改为如下所示,则两个线程并不能同步执行,因为此时两个线程的同步监视器不是同一个对象,不能起到同步的作用。

[java] view plain copy
 print?
  1. public static void main(String[] args)  
  2.     {  
  3.         Thread t = new SynchronizedTest1();  
  4.         t.start();  
  5.           
  6.         Thread t1 = new SynchronizedTest1();  
  7.         t1.start();  
  8.     }  

此时输出结果如下所示:

[java] view plain copy
 print?
  1. Thread-0 testSynchronizedMethod:0  
  2. Thread-1 testSynchronizedMethod:0  
  3. Thread-0 testSynchronizedMethod:1  
  4. Thread-1 testSynchronizedMethod:1  
  5. Thread-0 testSynchronizedMethod:2  
  6. Thread-1 testSynchronizedMethod:2  
  7. Thread-0 testSynchronizedMethod:3  
  8. Thread-1 testSynchronizedMethod:3  
  9. Thread-0 testSynchronizedMethod:4  
  10. Thread-1 testSynchronizedMethod:4  
  11. Thread-0 testSynchronizedMethod:5  
  12. Thread-1 testSynchronizedMethod:5  
  13. Thread-0 testSynchronizedMethod:6  
  14. Thread-1 testSynchronizedMethod:6  
  15. Thread-0 testSynchronizedMethod:7  
  16. Thread-1 testSynchronizedMethod:7  
  17. Thread-0 testSynchronizedMethod:8  
  18. Thread-1 testSynchronizedMethod:8  
  19. Thread-0 testSynchronizedMethod:9  
  20. Thread-1 testSynchronizedMethod:9  
若想修改后的main方法能够在两个线程之间同步运行,需要将testSynchronizedMethod方法声明为静态方法,这样两个线程的监视器是同一个对象(类对象),能够同步执行。修改后的代码如下所示:
[java] view plain copy
 print?
  1. public class SynchronizedTest1 extends Thread  
  2. {  
  3.     private static synchronized void testSynchronizedMethod()  
  4.     {  
  5.         for (int i = 0; i < 10; i++)  
  6.         {  
  7.             System.out.println(Thread.currentThread().getName()  
  8.                     + " testSynchronizedMethod:" + i);  
  9.   
  10.             try  
  11.             {  
  12.                 Thread.sleep(100);  
  13.             }  
  14.             catch (InterruptedException e)  
  15.             {  
  16.                 e.printStackTrace();  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     @Override  
  22.     public void run()  
  23.     {  
  24.         testSynchronizedMethod();  
  25.     }  
  26.   
  27.     public static void main(String[] args)  
  28.     {  
  29.         Thread t = new SynchronizedTest1();  
  30.         t.start();  
  31.           
  32.         Thread t1 = new SynchronizedTest1();  
  33.         t1.start();  
  34.     }  
  35. }  
输出结果如下:

[java] view plain copy
 print?
  1. Thread-0 testSynchronizedMethod:0  
  2. Thread-0 testSynchronizedMethod:1  
  3. Thread-0 testSynchronizedMethod:2  
  4. Thread-0 testSynchronizedMethod:3  
  5. Thread-0 testSynchronizedMethod:4  
  6. Thread-0 testSynchronizedMethod:5  
  7. Thread-0 testSynchronizedMethod:6  
  8. Thread-0 testSynchronizedMethod:7  
  9. Thread-0 testSynchronizedMethod:8  
  10. Thread-0 testSynchronizedMethod:9  
  11. Thread-1 testSynchronizedMethod:0  
  12. Thread-1 testSynchronizedMethod:1  
  13. Thread-1 testSynchronizedMethod:2  
  14. Thread-1 testSynchronizedMethod:3  
  15. Thread-1 testSynchronizedMethod:4  
  16. Thread-1 testSynchronizedMethod:5  
  17. Thread-1 testSynchronizedMethod:6  
  18. Thread-1 testSynchronizedMethod:7  
  19. Thread-1 testSynchronizedMethod:8  
  20. Thread-1 testSynchronizedMethod:9  
同步块的情况与同步方法类似,只是同步块将同步控制的粒度缩小,这样能够更好的发挥多线程并行执行的效率。
使用this对象控制同一对象实例之间的同步:

[java] view plain copy
 print?
  1. public class SynchronizedTest2 extends Thread  
  2. {  
  3.     private void testSynchronizedBlock()  
  4.     {  
  5.         synchronized (this)  
  6.         {  
  7.             for (int i = 0; i < 10; i++)  
  8.             {  
  9.                 System.out.println(Thread.currentThread().getName()  
  10.                         + " testSynchronizedBlock:" + i);  
  11.   
  12.                 try  
  13.                 {  
  14.                     Thread.sleep(100);  
  15.                 }  
  16.                 catch (InterruptedException e)  
  17.                 {  
  18.                     e.printStackTrace();  
  19.                 }  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     @Override  
  25.     public void run()  
  26.     {  
  27.         testSynchronizedBlock();  
  28.     }  
  29.   
  30.     public static void main(String[] args)  
  31.     {  
  32.         SynchronizedTest2 t = new SynchronizedTest2();  
  33.         t.start();  
  34.   
  35.         t.testSynchronizedBlock();  
  36.     }  
  37. }  
输出结果:

[java] view plain copy
 print?
  1. main testSynchronizedBlock:0  
  2. main testSynchronizedBlock:1  
  3. main testSynchronizedBlock:2  
  4. main testSynchronizedBlock:3  
  5. main testSynchronizedBlock:4  
  6. main testSynchronizedBlock:5  
  7. main testSynchronizedBlock:6  
  8. main testSynchronizedBlock:7  
  9. main testSynchronizedBlock:8  
  10. main testSynchronizedBlock:9  
  11. Thread-0 testSynchronizedBlock:0  
  12. Thread-0 testSynchronizedBlock:1  
  13. Thread-0 testSynchronizedBlock:2  
  14. Thread-0 testSynchronizedBlock:3  
  15. Thread-0 testSynchronizedBlock:4  
  16. Thread-0 testSynchronizedBlock:5  
  17. Thread-0 testSynchronizedBlock:6  
  18. Thread-0 testSynchronizedBlock:7  
  19. Thread-0 testSynchronizedBlock:8  
  20. Thread-0 testSynchronizedBlock:9  
使用class对象控制不同实例之间的同步:

[java] view plain copy
 print?
  1. public class SynchronizedTest2 extends Thread  
  2. {  
  3.     private void testSynchronizedBlock()  
  4.     {  
  5.         synchronized (SynchronizedTest2.class)  
  6.         {  
  7.             for (int i = 0; i < 10; i++)  
  8.             {  
  9.                 System.out.println(Thread.currentThread().getName()  
  10.                         + " testSynchronizedBlock:" + i);  
  11.   
  12.                 try  
  13.                 {  
  14.                     Thread.sleep(100);  
  15.                 }  
  16.                 catch (InterruptedException e)  
  17.                 {  
  18.                     e.printStackTrace();  
  19.                 }  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     @Override  
  25.     public void run()  
  26.     {  
  27.         testSynchronizedBlock();  
  28.     }  
  29.   
  30.     public static void main(String[] args)  
  31.     {  
  32.         Thread t = new SynchronizedTest2();  
  33.         t.start();  
  34.   
  35.         Thread t2 = new SynchronizedTest2();  
  36.         t2.start();  
  37.     }  
  38. }  

输出结果:

[java] view plain copy
 print?
  1. Thread-0 testSynchronizedBlock:0  
  2. Thread-0 testSynchronizedBlock:1  
  3. Thread-0 testSynchronizedBlock:2  
  4. Thread-0 testSynchronizedBlock:3  
  5. Thread-0 testSynchronizedBlock:4  
  6. Thread-0 testSynchronizedBlock:5  
  7. Thread-0 testSynchronizedBlock:6  
  8. Thread-0 testSynchronizedBlock:7  
  9. Thread-0 testSynchronizedBlock:8  
  10. Thread-0 testSynchronizedBlock:9  
  11. Thread-1 testSynchronizedBlock:0  
  12. Thread-1 testSynchronizedBlock:1  
  13. Thread-1 testSynchronizedBlock:2  
  14. Thread-1 testSynchronizedBlock:3  
  15. Thread-1 testSynchronizedBlock:4  
  16. Thread-1 testSynchronizedBlock:5  
  17. Thread-1 testSynchronizedBlock:6  
  18. Thread-1 testSynchronizedBlock:7  
  19. Thread-1 testSynchronizedBlock:8  
  20. Thread-1 testSynchronizedBlock:9  

使用synchronized关键字进行同步控制时,一定要把握好对象监视器,只有获得监视器的进程可以运行,其它都需要等待获取监视器。任何一个非null的对象都可以作为对象监视器,当synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例。


总结:

synchronized是通过软件(JVM)实现的,简单易用,即使在JDK5之后有了Lock,仍然被广泛地使用。
synchronized实际上是非公平的,新来的线程有可能立即获得监视器,而在等待区中等候已久的线程可能再次等待,不过这种抢占的方式可以预防饥饿。
synchronized只有锁只与一个条件(是否获取锁)相关联,不灵活,后来Condition与Lock的结合解决了这个问题。
多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。高并发的情况下会导致性能下降。ReentrantLock的lockInterruptibly()方法可以优先考虑响应中断。 一个线程等待时间过长,它可以中断自己,然后ReentrantLock响应这个中断,不再让这个线程继续等待。有了这个机制,使用ReentrantLock时就不会像synchronized那样产生死锁了。


参考资料:

JAVA并发编程学习笔记之synchronized
深入JVM锁机制1-synchronized

java 对象锁


相关文章推荐

java 多线程 同步 synchronized 的个人理解和用法

1.当 synchronized A方法被一个线程调用的时候(运行过程中), 另外一个线程调用A方法会block住,而并不是请求失败,如果此时在block住的线程实例上调用interrupt方法就会触...

Java线程(二):线程同步synchronized和volatile

上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程...

java的两种同步方式, Synchronized与ReentrantLock的区别

java在编写多线程程序时,为了保证线程安全,需要同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock。 相似点: 这两种同步方式有很多相似之处,它们都是加锁方式同...

Java线程同步:synchronized锁住的是代码还是对象

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在...

若还 不懂 java synchronized 同步,锁,对象wait,notify问题,看完这两段代码,解决问题。

看代码很累,特别看别人滴代码,又特别针对新人,但请你忍耐一下,看完这两个单独案例。 这两个个代码的功能一样,都是间断打印1、2、1、2……间隔1秒。 代码1: public class Out...
  • cnmm22
  • cnmm22
  • 2015年03月15日 05:24
  • 876

synchronized 同步锁(java)实例解析

0引言     在多线程应用场景中,同步锁是一种非常重要的机制,例如:ID号的分配,多个客户端分别与服务端建立连接,客户端并发请求的情况下,为提升吞吐量,服务端一般采用多线程处理请求,若无同步锁机制...

初学Java多线程:使用Synchronized块同步变量

初学Java多线程:使用Synchronized块同步变量 本文是Java多线程初学教程中的最后一部分,讲解如何使用Synchronized块同步变量。我们可以通过synchronized块来同...
  • ihrthk
  • ihrthk
  • 2012年03月05日 10:55
  • 491

关于对网上一则java synchronized 线程同步的分析

为了看一些synchronized相关的内容,查了网上的一些例子,然后糊涂了一个下午,最终搞懂了,作者可能是好心,但是感觉分析的不彻底,给看的人也容易造成困惑,把我的分析过程贴出来,本来代码比较乱,但...

Java线程同步:synchronized锁住的是代码还是对象

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在...

Java同步机制总结--synchronized关键字的使用

不久前用到了同步,现在回过头来对JAVA中的同步做个总结,以对前段时间工作的总结和自我技术的条理话。 JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java同步之synchronized
举报原因:
原因补充:

(最多只允许输入30个字)