Java 多线程编程总结

Java 多线程编程总结内容

一,synchronized 关键字的使用

 带有 synchronized 关键字的方法代表这个方法加锁。恰当而又灵活地运用 synchronized 关键字,是多线程编程的必修课。1、synchronized关键字的作用域有二种:

  1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
  2)是某个类的范围,synchronized static aStaticMethod(){}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
  2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象。
        synchronized(this)用于定义一个临界区(即是:其后面大括弧所包含的部分),以保证在多线程下只能有一个线程可以进入this对象的临界区。 也就是说synchronized(对象或者变量){},表示在{}内的这段代码中,对(对象或者变量)中的对象或者变量进行同步处理,也就是说当访问这段代码时,一个线程对对象或者变量的访问完成后才能够交给另外一个线程,即有了同步锁。使用 synchronized(对象或者变量),就是为了防止对象或者变量被同时访问,避免多个线程修改和读取对象或者变量同时出现的时候,使用这个对象或者变量的地方出现错误的判断,如 while(对象或者变量)。
  3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。

二、wait() 和 notify()的使用

主程序 ThreadA 的源代码如下:

[java]  view plain  copy
 print ?
  1. class ThreadA  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         ThreadB b = new ThreadB();  
  6.         b.start();  
  7.         System.out.println("b is start....");  
  8.         synchronized (b)// 括号里的b是什么意思,起什么作用?  
  9.         {  
  10.             try  
  11.             {  
  12.                 System.out  
  13.                         .println("Waiting for b to complete...");  
  14.                 b.wait();// 这一句是什么意思,究竟让谁wait?  
  15.                 System.out  
  16.                         .println("Completed.Now back to main thread");  
  17.             } catch (InterruptedException e)  
  18.             {  
  19.             }  
  20.         }  
  21.         System.out.println("Total is :" + b.total);  
  22.     }  
  23. }  

  ThreadB 的源代码如下:
[java]  view plain  copy
 print ?
  1. class ThreadB extends Thread  
  2. {  
  3.     int total;  
  4.     public void run()  
  5.     {  
  6.         synchronized (this)  
  7.         {  
  8.             System.out.println("ThreadB is running..");  
  9.             for (int i = 0; i < 100; i++)  
  10.             {  
  11.                 total += i;  
  12.                 System.out.println("total is " + total);  
  13.             }  
  14.             notify();  
  15.         }  
  16.     }  
  17. }  

  要分析这个程序,首先要理解 notify() 和 wait(),为什么在前几天纪录线程的时候没有纪录这两个方法呢,因为这两个方法本来就不属于 Thread 类,而是属于最底层的 object 基础类的,也就是说不光是 Thread,每个对象都有  notify 和wait 的功能,为什么?因为他们是用来操纵锁的,而每个对象都有锁,锁是每个对象的基础,既然锁是基础的,那么操纵锁的方法当然也是最基础了。
  再往下看之前呢,首先最好复习一下 Think in Java 的 14.3.1 中第 3 部分内容:等待和通知,也就是 wait() 和 notify 了。
  按照 Think in Java 中的解释,wait() 答应我们将线程置入“睡眠”状态,同时又“积极”地等待条件发生改变。而且只有在一个 notify() 或 notifyAll() 发生变化的时候,线程才会被唤醒,并检查条件是否有变。
  我们来解释一下这句话。
  “ wait() 答应我们将线程置入‘睡眠‘状态“,也就是说,wait 也是让当前线程阻塞的,这一点和 sleep 或者 suspend 是相同的。那和 sleep,suspend 有什么区别呢?
  区别在于“(wait) 同时又‘积极‘地等待条件发生改变“,这一点很要害,sleep 和 suspend 无法做到。因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着, 等到同步方法或者同步块里的程序全部运行完才有机会。在同步方法和同步块中,无论 sleep() 还是 suspend() 都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放。
  而 wait 却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行 wait() 期间调用线程对象中的其他同步方法!在其它情况下( sleep 啊,suspend 啊),这是不可能的。
  但是注重我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我 wait 所在的线程还是要把这个对象锁收回来的呀。wait 什么?就是 wait 别人用完了还给我啊!
  好,那怎么把对象锁收回来呢?
  第一种方法,限定借出去的时间。在 wait() 中设置参数,比如 wait(1000),以毫秒为单位,就表明我只借出去 1 秒钟。一秒钟之后,我自动收回。
  第二种方法,让借出去的人通知我,他用完了,要还给我了。这时,我马上就收回来。哎,假如我设了 1 小时之后收回,别人只用了半小时就完了,那怎么办呢?当然用完了就收回了,还管我设的是多长时间啊。
  那么别人怎么通知我呢?相信大家都可以想到了:notify(),这就是最后一句话“而且只有在一个 notify() 或 notifyAll() 发生变化的时候,线程才会被唤醒“的意思了。
  因此,我们可将一个 wait() 和 notify() 置入任何同步方法或同步块内部,无论在那个类里是否预备进行涉及线程的处理。而且实际上,我们也只能在同步方法或者同步块里面调用 wait() 和 notify()。
  这个时候我们来解释上面的程序,简直是易如反掌了。
  synchronized(b){...};的意思是定义一个同步块,使用 b 作为资源锁。b.wait();的意思是临时释放锁,并阻塞当前线程,好让其他使用同一把锁的线程有机会执行,在这里要用同一把锁的就是 b 线程本身。这个线程在执行到一定地方后用 notify() 通知 wait 的线程锁已经用完,待 notify() 所在的同步块运行完之后,wait 所在的线程就可以继续执行。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值