Java多线程之synchronized

本文通过三个测试类详细解析了Java中synchronized关键字的应用场景,包括同步方法、静态同步方法及同步块的使用方式与特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里通过三个测试类阐述了synchronized应用的不同场景


首先是最基本的synchronized Method的使用

  1. packagecom.jadyer.thread.sync;
  2. /**
  3. *SynchronizedMethodTest
  4. *@see===================================================================================================
  5. *@see概述:Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor)
  6. *@see说明:当synchronized关键字修饰一个方法时,则该方法为同步方法
  7. *@see当某个线程访问某个对象的synchronized方法时,则表示将该对象上锁
  8. *@see此时其它的任何线程,均无法访问该对象中的任何一个synchronized方法(但允许访问该对象中的非synchronized方法)
  9. *@see直到该线程所访问的synchronized方法执行完毕(或者抛出了异常)之后,该对象的锁才会被释放
  10. *@see此时其它的任何线程,才被允许访问该synchronized方法,或者是该对象中的其它synchronized方法
  11. *@see===================================================================================================
  12. *@see总结:如果一个对象有多个synchronized方法,某一时刻某个线程已经执行了该对象中的某一个synchronized方法
  13. *@see那么在该方法没有执行完毕之前,其它线程是无法访问该对象中的,包括该方法在内的,任何一个synchronized方法
  14. *@see重点在于判断Synchronized锁的是谁。如果该方法是静态的,则锁Class对象,否则锁的就是当前对象
  15. *@see===================================================================================================
  16. *@see补充:1)这只是针对多个线程操作同一个类的同一个对象的情况。www.linuxidc.com若多个线程操作同一个类的不同对象,则不存在这种情况
  17. *@see2)Java中的volatile变量也可以看作是一种"程度较轻的synchronized"
  18. *@see关于volatile的更多信息,请参考http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
  19. *@see备注:实际项目中,用到的更多的还是JDK5.0开始推出的Java并发包,即java.util.concurrent包里面的工具类
  20. *@seejava.util.concurrent可以非常细粒度的实现并发。比如线程访问到了一个已被锁的对象,它可以让这个线程等到10秒
  21. *@see10秒后如果该对象仍未被解锁,那么就可以返回给用户超时的提示等,而如果使用synchronized则是无法这么精确控制的
  22. *@see===================================================================================================
  23. *@see注意:1)当synchronized方法执行完或者发生异常时,会自动释放锁
  24. *@see2)被synchronized保护的数据应该是private的,否则也就没必要去通过方法来访问这个public的数据了
  25. *@see===================================================================================================
  26. *@author宏宇
  27. *@createFeb21,20125:29:39PM
  28. */
  29. publicclassSynchronizedTest{
  30. publicstaticvoidmain(String[]args){
  31. Bankbank=newBank();
  32. Threadtt11=newThread(newThreadRMB(bank));
  33. //new一个新的Bank对象。此时存在两个Bank对象,并且它们属于同一个类的不同的对象
  34. //如要验证多个线程操作同一个类的不同的对象的synchronized方法,只需取消注释该行代码即可
  35. //bank=newBank();
  36. Threadtt22=newThread(newThreadDollar(bank));
  37. tt11.start();
  38. tt22.start();
  39. }
  40. }
  41. classThreadRMBimplementsRunnable{
  42. privateBankbank;
  43. publicThreadRMB(Bankbank){
  44. this.bank=bank;
  45. }
  46. @Override
  47. publicvoidrun(){
  48. bank.getRMB();
  49. }
  50. }
  51. classThreadDollarimplementsRunnable{
  52. privateBankbank;
  53. publicThreadDollar(Bankbank){
  54. this.bank=bank;
  55. }
  56. @Override
  57. publicvoidrun(){
  58. bank.getDollar();
  59. }
  60. }
  61. classBank{
  62. publicsynchronizedvoidgetRMB(){
  63. for(inti=0;i<20;i++){
  64. try{
  65. Thread.sleep((long)(Math.random()*1000));
  66. }catch(InterruptedExceptione){
  67. e.printStackTrace();
  68. }
  69. System.out.println(Thread.currentThread().getName()+":"+i);
  70. }
  71. }
  72. publicsynchronizedvoidgetDollar(){
  73. for(inti=0;i<20;i++){
  74. try{
  75. Thread.sleep((long)(Math.random()*1000));
  76. }catch(InterruptedExceptione){
  77. e.printStackTrace();
  78. }
  79. System.out.println(Thread.currentThread().getName()+":"+i);
  80. }
  81. }
  82. }
下面演示的是synchronized static Method的使用
  1. packagecom.jadyer.thread.sync;
  2. /**
  3. *SynchronizedStaticMethodTest
  4. *@see说明:如果某个synchronized方法是static的
  5. *@see那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是该方法所在的对象所对应的Class对象
  6. *@see因为Java中无论一个类有多少个对象,这些对象都会对应唯一的一个Class对象
  7. *@see因此当线程分别访问同一个类的两个对象的两个static的synchronized方法时,它们的执行顺序也是顺序执行的
  8. *@see即一个线程先执行一个static的synchronized方法,执行完毕后,另一个线程才开始执行另一个static的synchronized方法
  9. *@see总结:重点在于判断synchronized锁的是谁。www.linuxidc.com如果该方法是静态的,则锁Class对象,否则锁的就是当前对象
  10. *@author宏宇
  11. *@createFeb21,20125:29:39PM
  12. */
  13. publicclassSynchronizedStaticTest{
  14. publicstaticvoidmain(String[]args){
  15. Bankbank=newBank();
  16. Threadtt11=newThread(newThreadRMB(bank));
  17. Threadtt22=newThread(newThreadDollar(bank));
  18. tt11.start();
  19. tt22.start();
  20. }
  21. }
  22. classThreadRMBimplementsRunnable{
  23. privateBankbank;
  24. publicThreadRMB(Bankbank){
  25. this.bank=bank;
  26. }
  27. @Override
  28. publicvoidrun(){
  29. bank.getRMB();
  30. }
  31. }
  32. classThreadDollarimplementsRunnable{
  33. privateBankbank;
  34. publicThreadDollar(Bankbank){
  35. this.bank=bank;
  36. }
  37. @Override
  38. publicvoidrun(){
  39. bank.getDollar();
  40. }
  41. }
  42. classBank{
  43. //如要验证synchronized锁同一个类的对象,和锁它的Class对象的区别
  44. //可去掉static关键字,再查看控制台打印,即publicsynchronizedvoidgetRMB()
  45. publicsynchronizedstaticvoidgetRMB(){
  46. for(inti=0;i<20;i++){
  47. try{
  48. Thread.sleep((long)(Math.random()*1000));
  49. }catch(InterruptedExceptione){
  50. e.printStackTrace();
  51. }
  52. System.out.println(Thread.currentThread().getName()+":"+i);
  53. }
  54. }
  55. publicsynchronizedstaticvoidgetDollar(){
  56. for(inti=0;i<20;i++){
  57. try{
  58. Thread.sleep((long)(Math.random()*1000));
  59. }catch(InterruptedExceptione){
  60. e.printStackTrace();
  61. }
  62. System.out.println(Thread.currentThread().getName()+":"+i);
  63. }
  64. }
  65. }
最后演示的是synchronized Block的使用
  1. packagecom.jadyer.thread.sync;
  2. /**
  3. *SynchronizedBlockTest
  4. *@author宏宇
  5. *@createFeb21,20125:29:39PM
  6. */
  7. publicclassSynchronizedBlockTest{
  8. publicstaticvoidmain(String[]args){
  9. Bankbank=newBank();
  10. Threadtt11=newThread(newThreadRMB(bank));
  11. //如果要验证synchronized(this)锁的是当前类的对象,而非当前类的Class对象
  12. //则可取消注释该行代码,再观察控制台打印效果。效果应该是两个线程并发执行的输出
  13. //bank=newBank();
  14. Threadtt22=newThread(newThreadDollar(bank));
  15. tt11.start();
  16. tt22.start();
  17. }
  18. }
  19. classThreadRMBimplementsRunnable{
  20. privateBankbank;
  21. publicThreadRMB(Bankbank){
  22. this.bank=bank;
  23. }
  24. @Override
  25. publicvoidrun(){
  26. bank.getRMB();
  27. }
  28. }
  29. classThreadDollarimplementsRunnable{
  30. privateBankbank;
  31. publicThreadDollar(Bankbank){
  32. this.bank=bank;
  33. }
  34. @Override
  35. publicvoidrun(){
  36. bank.getDollar();
  37. }
  38. }
  39. /**
  40. *Bank
  41. *@see说明:synchronized块的写法:synchronized(object){//TODO...},它表示线程在执行的时候,会对object对象上锁
  42. *@see通常会把java.lang.Object对象传进来,事实上这里可以传进来任何的对象
  43. *@see因为它是一个没有实际作用的对象,其仅仅起到锁的作用,就像一个标识一样
  44. *@see作用:它表示,如果线程能够进入到这里,即执行到这里,那么,就将object对象锁上
  45. *@see如果另一个线程也执行到这里,发现object对象已上锁,则会等待其解锁后,才会去执行synchronized块里面的代码
  46. *@see补充:synchronized(this)表示对当前类的对象上锁。注意,它锁的不是当前类的Class对象
  47. *@seesynchronized(Bank.class)表示对当前类的Class对象上锁
  48. *@author宏宇
  49. *@createFeb22,20122:29:16AM
  50. */
  51. classBank{
  52. privateObjectobj11=newObject();
  53. privateObjectobj22=newObject();
  54. publicvoidgetRMB(){
  55. //synchronized(obj11){
  56. synchronized(Bank.class){
  57. for(inti=0;i<20;i++){
  58. try{
  59. Thread.sleep((long)(Math.random()*1000));
  60. }catch(InterruptedExceptione){
  61. e.printStackTrace();
  62. }
  63. System.out.println(Thread.currentThread().getName()+":"+i);
  64. }
  65. }
  66. }
  67. publicvoidgetDollar(){
  68. //synchronized(obj11){
  69. //synchronized(obj22){
  70. synchronized(this){
  71. for(inti=0;i<20;i++){
  72. try{
  73. Thread.sleep((long)(Math.random()*1000));
  74. }catch(InterruptedExceptione){
  75. e.printStackTrace();
  76. }
  77. System.out.println(Thread.currentThread().getName()+":"+i);
  78. }
  79. }
  80. }
  81. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值