Java实用教程第15讲Java多线程(二).ppt_第1页
Java实用教程第15讲Java多线程(二).ppt_第2页
Java实用教程第15讲Java多线程(二).ppt_第3页
Java实用教程第15讲Java多线程(二).ppt_第4页
Java实用教程第15讲Java多线程(二).ppt_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第15讲 Java多线程(二),15.1 访问共享资源 15.2 线程间协作 15.3 死锁 15.4 本讲小结,将一个任务拆分成多个独立执行的子任务,这些子任务可以并行执行,这是使用Java多线程编程的好处,但这些子任务同时访问一个资源时,就会造成访问的冲突,在解决冲突时还要避免产生死锁,另外,有时多个子任务之间需要协调通信来共同完成一个任务。,15.1 访问共享资源,多个线程同时访问同一存储空间时可能会出现访问冲突。如:两个线程访问同一个对象时,一个线程向对象中存储数据,另一个线程读取该数据。当第一个线程还没有完成存储操作时,第二个线程就开始读取数据,这时会产生了混乱。,15.1.1 访问

2、冲突,考虑下面的程序:,AccessConflict.java class DataClass private int data=0; public void increase() int nd=data; try Thread.sleep(100); catch (Exception e) data=nd+1; public int getData() return data; ;,class NThread extends Thread DataClass d; NThread(DataClass d) this.d=d; boolean alive=true; public void r

3、un() for(int i=0;i100;i+) d.increase(); alive=false; ; public class AccessConflict public static void main(String args) DataClass d=new DataClass(); NThread t1=new NThread(d); NThread t2=new NThread(d); t1.start(); t2.start(); while(t1.alive|t2.alive); System.out.println(data=+d.getData(); ,15.1.2 解

4、决冲突,防止冲突的方法就是当资源被一个线程访问时,为这个资源加锁。 Java使用关键字synchronized来实现这一过程。 使用关键字synchronized修饰的方法称为同步方法,当线程调用非静态的synchronized方法时,自动获得synchronized所标示的与正在执行代码类的当前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。 关键字synchronized可以修饰方法,一个对象只有一个锁。所以,如果一个线程获得该锁,这时其它线程要想获得该对象的锁就必须等待,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对

5、象上的synchronized方法或代码块,直到该锁被释放。,同步时所注意的问题: (1)当程序运行到synchronized同步方法或代码块时才该对象锁才起作用; (2)使用private修饰域,可以防止其它线程直接访问域; (3)线程睡眠时,它所持的任何锁都不会释放; (4)一个线程可以同时获得多个锁; (5)同步方法虽然可以解决同步问题,但也存在缺陷,如果一个同步方法需要执行的时间很长,将会大大影响系统的效率,这时进来使用synchronized块。,15.1.3 静态方法同步,synchronized 修饰的静态方法可以在类的范围内防止对static数据的并发访问,如: public

6、synchronized static void f() synchronized 修饰的静态方法属于某个类的范围,防止多个线程同时访问这个类中的synchronized 修饰的静态方法,它可以对类的所有对象实例起作用。而synchronized的实例方法是某实例的范围,它防止多个线程同时访问这个实例中的synchronized方法。,15.2 线程间协作,可以使用锁(互斥)来同步多个线程,那么如何实现多个线程间的协作呢?多个线程协作的关键在于它们之间的相互通信。互斥可以保证同一时刻只有一个线程相应某个信号,在互斥的基础上再添加某种途径,可以使线程本身挂起,直到某些条件发生变化再转入就绪状态。

7、,线程间的通信通过“等待-通知”机制来实现,Object类中的wait()和notify()方法实现了这种机制。 wait()方法可以使线程等待某个条件发生变化,而这种条件将由另外一个线程来改变。wait()不是忙等待,线程在wait()期间被挂起,可以通过notify()或notifyAll()被唤醒。 有两种形式的wait(): (1)public final void wait() (2)public final void wait(long timeout, int nanos),这两种重载的wait()都能使线程等待,只不过第一个wait()是通过notify()或notifyAll

8、()被唤醒。第二个wait()接受毫秒数作为参数,是指在此期间暂停,但这样sleep()与yield()不同: (1)在wait()期间对象锁是释放的,能够避免死锁。而在sleep()和yield()时,对象锁并没有被释放,容易产生死锁。 (2)可以通过notify()、notifyAll()来唤醒wait(),而使用“令时间到期”的方式唤醒wait(long timeout, int nanos)。,15.3 死锁,锁机制(互斥)可以解决访问冲突,但线程可以陷入阻塞,所以会产生一种情况:第一个线程已经获得了第一个锁,在等待第二个锁,而第二个锁又被第二个线程把持,这样以此类推,最后一个线程又等

9、待第一个锁,这样循环下去,没有哪个线程能继续下去,这种情况被称为死锁。,哲学家就餐问题是一个典型的死锁例证。 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条。哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。上述问题会产生死锁的情况,当5个哲学家都拿起自己右手边的筷子,准备拿左手边的筷子时产生死锁现象。,解决办法: (1)添加一个服务生,只有当经过服务生同意之后才能拿筷子,服务生负责避免死锁发生。 (2)每个哲学家必须确定自己左右手的筷子都可用的时候,才能同时拿起两只筷子进餐,吃完之后同时放下两只筷子。 (3)规定每个哲学家拿筷子时必须拿序号小的那只,这样最后一位未拿到筷子的哲学家只剩下序号大的那只筷子,不能拿起,剩下的这只筷子就可以被其他哲学家使用,避免了死锁。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论