[转帖]   Java同步之synchronized_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 13096 | 回复: 0   主题: [转帖]   Java同步之synchronized        下一篇 
    本主题由 guoyongwei 于 2013-3-13 11:34:28 置为精华
guoyongwei
注册用户
等级:少校
经验:910
发帖:52
精华:6
注册:2013-3-11
状态:离线
发送短消息息给guoyongwei 加好友    发送短消息息给guoyongwei 发消息
发表于: IP:您无权察看 2013-3-11 16:11:44 | [全部帖] [楼主帖] 楼主

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


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

  1. publicclass SynchronizedTest1 extends Thread 
  2.       privatesynchronizedvoid testSynchronizedMethod() 
  3.        { 
  4.             for (int i = 0; i < 10; i++) 
  5.              { 
  6.                    System.out.println(Thread.currentThread().getName() 
  7.                    + " testSynchronizedMethod:" + i); 
  8.                   
  9.                   try
  10.                    { 
  11.                          Thread.sleep(100); 
  12.                    } 
  13.                   catch (InterruptedException e) 
  14.                    { 
  15.                          e.printStackTrace(); 
  16.                    } 
  17.              } 
  18.        } 
  19.       
  20.       @Override
  21.       publicvoid run() 
  22.        { 
  23.              testSynchronizedMethod(); 
  24.        } 
  25.       
  26.       publicstaticvoid main(String[] args) 
  27.        { 
  28.             
  29.              SynchronizedTest1 t = new SynchronizedTest1(); 
  30.              t.start(); 
  31.              t.testSynchronizedMethod(); 
  32.        } 

运行该程序输出结果为:

  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方法修改为如下所示,则两个线程并不能同步执行,因为此时两个线程的同步监视器不是同一个对象,不能起到同步的作用。

public static void main(String[] args)
{
      Thread t = new SynchronizedTest1();
      t.start();
      Thread t1 = new SynchronizedTest1();
      t1.start();
}


此时输出结果如下所示:

  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方法声明为静态方法,这样两个线程的监视器是同一个对象(类对象),能够同步执行。修改后的代码如下所示:

  1. publicclass SynchronizedTest1 extends Thread 
  2.       privatestaticsynchronizedvoid testSynchronizedMethod() 
  3.        { 
  4.             for (int i = 0; i < 10; i++) 
  5.              { 
  6.                    System.out.println(Thread.currentThread().getName() 
  7.                    + " testSynchronizedMethod:" + i); 
  8.                   
  9.                   try
  10.                    { 
  11.                          Thread.sleep(100); 
  12.                    } 
  13.                   catch (InterruptedException e) 
  14.                    { 
  15.                          e.printStackTrace(); 
  16.                    } 
  17.              } 
  18.        } 
  19.       
  20.       @Override
  21.       publicvoid run() 
  22.        { 
  23.              testSynchronizedMethod(); 
  24.        } 
  25.       
  26.       publicstaticvoid main(String[] args) 
  27.        { 
  28.              Thread t = new SynchronizedTest1(); 
  29.              t.start(); 
  30.             
  31.              Thread t1 = new SynchronizedTest1(); 
  32.              t1.start(); 
  33.        } 

输出结果如下:

  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对象控制同一对象实例之间的同步:

  1. publicclass SynchronizedTest2 extends Thread 
  2.       privatevoid testSynchronizedBlock() 
  3.        { 
  4.             synchronized (this) 
  5.              { 
  6.                   for (int i = 0; i < 10; i++) 
  7.                    { 
  8.                          System.out.println(Thread.currentThread().getName() 
  9.                          + " testSynchronizedBlock:" + i); 
  10.                         
  11.                         try
  12.                          { 
  13.                                Thread.sleep(100); 
  14.                          } 
  15.                         catch (InterruptedException e) 
  16.                          { 
  17.                                e.printStackTrace(); 
  18.                          } 
  19.                    } 
  20.              } 
  21.        } 
  22.       
  23.       @Override
  24.       publicvoid run() 
  25.        { 
  26.              testSynchronizedBlock(); 
  27.        } 
  28.       
  29.       publicstaticvoid main(String[] args) 
  30.        { 
  31.              SynchronizedTest2 t = new SynchronizedTest2(); 
  32.              t.start(); 
  33.             
  34.              t.testSynchronizedBlock(); 
  35.        } 

输出结果:

  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对象控制不同实例之间的同步:

public class SynchronizedTest2 extends Thread
{
      private void testSynchronizedBlock()
      {
            synchronized (SynchronizedTest2.class)
            {
                  for (int i = 0; i < 10; i++)
                  {
                        System.out.println(Thread.currentThread().getName()
                        + " testSynchronizedBlock:" + i);
                        try
                        {
                              Thread.sleep(100);
                        }
                        catch (InterruptedException e)
                        {
                              e.printStackTrace();
                        }
                  }
            }
      }
      @Override
      public void run()
      {
            testSynchronizedBlock();
      }
      public static void main(String[] args)
      {
            Thread t = new SynchronizedTest2();
            t.start();
            Thread t2 = new SynchronizedTest2();
            t2.start();
      }
}


输出结果:

Thread-0 testSynchronizedBlock:0
Thread-0 testSynchronizedBlock:1
Thread-0 testSynchronizedBlock:2
Thread-0 testSynchronizedBlock:3
Thread-0 testSynchronizedBlock:4
Thread-0 testSynchronizedBlock:5
Thread-0 testSynchronizedBlock:6
Thread-0 testSynchronizedBlock:7
Thread-0 testSynchronizedBlock:8
Thread-0 testSynchronizedBlock:9
Thread-1 testSynchronizedBlock:0
Thread-1 testSynchronizedBlock:1
Thread-1 testSynchronizedBlock:2
Thread-1 testSynchronizedBlock:3
Thread-1 testSynchronizedBlock:4
Thread-1 testSynchronizedBlock:5
Thread-1 testSynchronizedBlock:6
Thread-1 testSynchronizedBlock:7
Thread-1 testSynchronizedBlock:8
Thread-1 testSynchronizedBlock:9


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




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论