线程同步方法

用synchronized关键字修饰同步方法

同步有几种实现方法,都是什么?

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InerrupteException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待线程,而是由JVM确定唤醒哪个线程,而不是按优先级。

Allnotify():唤醒所有处于等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

同步是多线程中的重要概念。

同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。

给一个方法增加synchronized修饰符之后使之成为同步方法,这个方法可以是静态方法和非晶态方法,但不恩能够是抽象类的抽象方法,也不能是接口中的接口方法。

public synchronized void aMethod() {  

    // do something  

}  

public static synchronized void anotherMethod() {  

    // do something  

}  

线程在执行同步方法时是具有排他性的,当任意一个线程既然怒到一个对象的人一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任一个同步方法,知道这个线程执行完它所电泳的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某一个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。

同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。如果这个方法是静态同步方法呢?那么

那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。 

如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块。

synchronized 关键字用于保护共享数据。请大家注意“共享数据”,你一定要分清哪些数据是共享数据,

  public class ThreadTest implements Runnable{ 
  public synchronized void run(){ 
  for(int i=0;i<10;i++) { 
  System.out.print(" " + i); 
  } 
  } 
  public static void main(String[] args) { 
  Runnable r1 = new ThreadTest(); //也可写成ThreadTest r1 = new ThreadTest();
  Runnable r2 = new ThreadTest(); 
  Thread t1 = new Thread(r1); 
  Thread t2 = new Thread(r2); 
  t1.start(); 
  t2.start(); 
  }}

在这个程序中,run()虽然被加上了synchronized 关键字,但保护的不是共享数据。因为这个程序中的t1,t2 是两个对象(r1,r2)的线程。而不同的对象的数据是不同的,r1,r2 有各自的run()方法,所以输出结果无法预知

  public class ThreadTest implements Runnable{ 
  public synchronized void run(){ 
  for(int i=0;i<10;i++){ 
  System.out.print(" " + i); 
  } 
  } 
  public static void main(String[] args){ 
  Runnable r = new ThreadTest(); 
  Thread t1 = new Thread(r); 
  Thread t2 = new Thread(r); 
  t1.start(); 
  t2.start(); 
  }}

如果你运行1000 次这个程序,它的输出结果也一定每次都是:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。因为这里的synchronized 保护的是共享数据。t1,t2 是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run()方法时,由于run()受synchronized保护,所以同一个对象的其他线程(t2)无法访问synchronized 方法(run 方法)。只有当t1执行完后t2 才有机会执行。

  public class ThreadTest implements Runnable{ 
  public void run(){ 
  synchronized(this){ 
  for(int i=0;i<10;i++){ 
  System.out.print(" " + i); 
  }} } 
  public static void main(String[] args){ 
  Runnable r = new ThreadTest(); 
  Thread t1 = new Thread(r); 
  Thread t2 = new Thread(r); 
  t1.start(); 
  t2.start(); 
  }}

这个程序与示例3 的运行结果一样。在可能的情况下,应该把保护范围缩到最小,可以用示例4 的形式,this 代表“这个对象”。没有必要把整个run()保护起来,run()中的代码只有一个for循环,所以只要保护for 循环就可以了。 

  public class ThreadTest implements Runnable{ 
  public void run(){ 
  for(int k=0;k<5;k++){ 
  System.out.println(Thread.currentThread().getName()+ " : for loop : " + k); 
  } 
  synchronized(this){ 
  for(int k=0;k<5;k++) { 
  System.out.println(Thread.currentThread().getName()+ " : synchronized for loop : " + k); 
  }} } 
  public static void main(String[] args){ 
  Runnable r = new ThreadTest(); 
  Thread t1 = new Thread(r,"t1_name"); 
  Thread t2 = new Thread(r,"t2_name"); 
  t1.start(); 
  t2.start(); 
  } } 
  运行结果: 
  t1_name : for loop : 0 
  t1_name : for loop : 1 
  t1_name : for loop : 2 
  t2_name : for loop : 0 
  t1_name : for loop : 3 
  t2_name : for loop : 1 
  t1_name : for loop : 4 
  t2_name : for loop : 2 
  t1_name : synchronized for loop : 0 
  t2_name : for loop : 3 
  t1_name : synchronized for loop : 1 
  t2_name : for loop : 4 
  t1_name : synchronized for loop : 2 
  t1_name : synchronized for loop : 3 
  t1_name : synchronized for loop : 4 
  t2_name : synchronized for loop : 0 
  t2_name : synchronized for loop : 1 
  t2_name : synchronized for loop : 2 
  t2_name : synchronized for loop : 3 
t2_name : synchronized for loop : 4

第一个for 循环没有受synchronized 保护。对于第一个for 循环,t1,t2 可以同时访问。运行结果表明t1 执行到了k=2 时,t2 开始执行了。t1 首先执行完了第一个for 循环,此时t2还没有执行完第一个for 循环(t2 刚执行到k=2)。t1 开始执行第二个for 循环,当t1 的第二个for 循环执行到k=1 时,t2 的第一个for 循环执行完了。t2 想开始执行第二个for 循环,但由于t1 首先执行了第二个for 循环,这个对象的锁标志自然在t1 手中(synchronized 方法的执行权也就落到了t1 手中),在t1 没执行完第二个for 循环的时候,它是不会释放锁标志的。所以t2 必须等到t1 执行完第二个for 循环后,它才可以执行第二个for 循环。  






转载于:https://my.oschina.net/u/347414/blog/152655

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值