收藏 分享(赏)

7.Java 多线程.ppt

上传人:精品资料 文档编号:10395541 上传时间:2019-11-06 格式:PPT 页数:66 大小:1.35MB
下载 相关 举报
7.Java 多线程.ppt_第1页
第1页 / 共66页
7.Java 多线程.ppt_第2页
第2页 / 共66页
7.Java 多线程.ppt_第3页
第3页 / 共66页
7.Java 多线程.ppt_第4页
第4页 / 共66页
7.Java 多线程.ppt_第5页
第5页 / 共66页
点击查看更多>>
资源描述

1、7. Java 多线程,2019/11/6,2,内容,多线程基本概念 Java多线程 创建多线程 线程的状态控制 Java多线程的一些问题 小结注: 本课件部分材料来自网络,2019/11/6,3,1 多线程基本概念,文件,输入输出装置,各种系统资源,数据区段,程序区段,只有一个地方在执行,文件,输入输出装置,各种系统资源,程序区段,同时有数个地方在执行,传统的进程,多线程的任务,2019/11/6,4,多线程的优势: 减轻编写交互频繁、涉及面多的程序的困难 程序的吞吐量会得到改善 由多个处理器的系统,可以并行运行不同的线程(否则,任何时刻只有一个线程在运行,形成并发运行),2019/11/6

2、,5,线程与进程的区别: 多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响 线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小,多线程编程原则,安全性: 如果两个以上的线程访问同一对象时,一个线程会损坏另一个线程的数据,这就违反了安全性原则 可行性: 如果仅仅实现了安全性,程序却在某一点后不能继续执行或者多个线程发生死锁,那么这样的程序也不能作为真正的多线程程序来应用 高性能: 多线程的目的是为了增加程序运行的性能,2019/11/6,6,2019/11/6,7,2. Java线程概念,对线程的综合

3、支持是Java技术的一个重要特色.它提供了thread类、监视器和条件变量的技术. 虽然许多操作系统支持多线程,但若要用C或C+编写多线程程序是十分困难的,因为它们对数据同步的支持不充分.,线程对象和线程的区别: 线程对象是可以产生线程的对象比如在java平台中Thread对象,Runnable对象。 线程,是指正在执行的一个指令序列。在java平台上是指从一个线程对象的start()开始,运行run方法体中的那一段相对独立的过程。,2019/11/6,8,思考如果我们成功编译了该java文件,然后运行 发生的过程 Jvm进程启动, JVM产生一个主线程 还有一些其它线程,例如垃圾回收等,20

4、19/11/6,9,class BeginClasspublic static void main(String args)for(int i=0;i100;i+)System.out.println(“Hello,World!“);,剖析多线程程序,2019/11/6,10,class MyThread extends Thread public void run() System.out.println(“Thread say:Hello,World!“); public class MoreThreadspublic static void main(String args)new My

5、Thread();new MyThread().start(); System.out.println(“Main say:Hello,World“); ,2019/11/6,11,3. 创建多线程,Runnable 与Thread 1. public class mythread extends Applet implements Runnable(小应用或已经是某个类的子类时) 2. 继承类Threadpublic class mythread extends Thread 创建方法: newthread=new Thread(this); newthread.start();,2019/

6、11/6,12,Runable与Thread的区别 使用runable最主要的原因是:java缺少多重继承的机制,可能你的类已经继承了其他类了,这时你无法继承自thread类,只能用runnable了 Runable 创建的线程共享数据区,public class Test public static void main(String args) throws Exception MyThread mt = new MyThread(); mt.start(); mt.join(); Thread.sleep(3000); mt.start(); 输出:Exception in thread

7、“main“ java.lang.IllegalThreadStateException 说明:通过Thread实例的start(),一个Thread的实例只能产生一个线程,2019/11/6,13,2019/11/6,14,class R implements Runnable private int x = 0; public void run() for(int i=0;i100;i+)try Thread.sleep(10); catch(Exception e) System.out.println(x+); ,public class Test public static void

8、 main(String args) throws Exception R r = new R(); for(int i=0;i10;i+) new Thread(r).start(); ,2019/11/6,15,package debug; import java.io.*; import java.lang.Thread; class MyThread extends Thread public int x = 0; public void run() System.out.println(+x); class R implements Runnable private int x =

9、0; public void run() System.out.println(+x); ,public class Test public static void main(String args) throws Exception for(int i=0;i10;i+) Thread t = new MyThread();t.start(); Thread.sleep(10000);/让上面的线程运行完成 R r = new R(); for(int i=0;i10;i+) Thread t = new Thread(r); t.start(); ,2019/11/6,16,重要的方法,s

10、tart() 从CPU中申请另一个线程空间来执行run()方法中的代码 run() 是运行线程的主体,启动线程时,由java直接调用 public void run() 如果你不调用Start, 直接调用run, 会如何? stop() 停止线程, 调用线程的 newthread.stop() (不是安全的处理)sleep方法 暂停线程的执行,让其它线程得到机会,sleep要丢出异常,必须抓住: Trysleep(100)catch(InterruptedException e),2019/11/6,17,import javax.swing.*; public class Applet1 e

11、xtends JAppletmythread t1=new mythread();public void init() t1.start(); class mythread extends Thread public void run() for (int i=0;i4;i+) System.out.println( “ “+i); try sleep(400);catch(InterruptedException e) ,2019/11/6,18,7.2 创建线程的方式,import javax.swing.*; import java.awt.*;public class Applet1

12、extends JApplet C t1=new C(this);public void init() t1.start();public void paint(Graphics g) g.drawString(“Hello,java“,10,50);class C extends Thread Applet1 a;C(Applet1 b) a=b; public void run() while(true) a.repaint(); trysleep(400); catch(InterruptedException e),join:等待线程执行完毕,被等待的那个线程不结束,当前线程就一直等待

13、.,2019/11/6,19,public class Test public static void main(String args) throws ExceptionMyThread mt = new MyThread(); mt.start(); mt.join();System.out.println(101); ,2019/11/6,20,其它常用的方法isAlive :判断线程目前是否正在执行状态中if(newthread.isAlive() newthread.stop();resume:要求被暂停线程继续执行suspend:暂停线程的执行 yield:将执行的权力交给其它线程

14、,自己到队列的最后等待.,2019/11/6,21,线程的优先权 某一时刻只有一个线程在执行,调度策略为固定优先级调度. newthread.setPriority(Thread.MIN_PRIORITY) 级别有:MIN-PRIORITYNOM_PRIORITYMAX-PRIORITY 自私的线程:有很高的优先权的线程,不主动睡眠或让出处理器控制权.,2019/11/6,22,4. 线程的状态控制,线程的状态,2019/11/6,23,当一个线程执行完所有语句后就自动终止 调用线程的stop()方法,也可以强制终止线程,可能产生不完整的残废数据 。 如果希望线程正常终止,可采用标记来使线程中

15、的run()方法退出,2019/11/6,24,public class Xyz implements Runnable private boolean timeToQuit=false;public void run() while (!timeToQuit)/clean up before run() ends;public void stopRunning() timeToQuit=true; ,2019/11/6,25,public class ControlThread private Runnable r=new Xyz();private Thread t=new Thread(

16、r);public void startThread() t.start(); publi void stopThread() r.stopRunning(); ,2019/11/6,26,暂停线程的执行等待条件满足再执行 下面的例子显示线程的挂起和唤醒 Applet第一次开始时,线程被启动 浏览器改变页面时,小应用程序的stop()方法被调用,线程被挂起. 浏览器回到原来的页面时,线程被唤醒.,2019/11/6,27,public void start() if (mythread=null)mythread=new Thread(); mythread.start();else myth

17、read.resume(); public void run() while(true) trysleep(100);catch(InterruptedException e) public void stop() mythread.suspend(); .,2019/11/6,28,5 . Java多线程问题,执行顺序 多个线程运行时,调度策略为固定优先级调度.级别相同时,由操作系统按时间片来分配 下面给出的例子中,共运行三个线程,它们做同样的事, 每次打印循环次数和自己的序列号,运行结果表明,它们并不是连续运行的. 如果给某个线程赋予较高的优先权,则发现这个进程垄断控制权thread.se

18、tPriority(Thread.MAX_PRIORITY),2019/11/6,29,7.3 多线程问题,/多个进程运行时执行顺序是交叉的 public class MyThread extends Threadint threadNum;public static void main(String args) MyThread array=new MyThread3;for (int i=0;i“ );trysleep(1000);catch(InterruptedException e);System.out.println(“thread “+threadNum+ “bye.“); ,

19、2019/11/6,30,如何写多线程,1.分别定义不同的线程类,在各自的run方法中定义线程的工作class mythread1 extends Thread public void run. class mythread2 extends Thread public void run. 2. 在主类中实例化各线程类,并启动线程.public class demo extends Applet public void init() mythread t1=new mythread1();mythread t2=new mythread2();t1.start(); t2.start(); ,

20、2019/11/6,31,练习:将窗口分为上下两个区,分别运行两个线程,一个在上面的区域中显示由右向左游动的字符串,另一个在下面的区域从左向右游动的字符串. 方法一: 一个线程,在paint方法中使用两个输出字符串的语句 public void paint(Graphics g) if y1200 y2=0 else y2=y2+10;g.drawString(“hello, Java!”,20,y1,);g.drawString(“hello, Java!”,40,y2,); ,2019/11/6,32,方法二:定义两个类,运行各自的线程,各自有自己的paint()方法. 注意: 两个App

21、let必须是panel类或者是canvas类,将Applet的区域分成两块,否则不能运行paint语句.,2019/11/6,33,import javax.swing.*; import java.awt.*;public class Applet1 extends JApplet C t1,t2;myCanvas c1,c2;Container contentPane = getContentPane( );public void init() c1=new myCanvas();c2=new myCanvas();contentPane.setLayout(new GridLayout(

22、2,1);contentPane.validate(); contentPane.add(c1);contentPane.add(c2);t1=new C(c1,5);t2=new C(c2,-5);t1.start();t2.start(); ,class myCanvas extends Canvas public void paint(Graphics g, int x,int y) g.drawString(“Hello World“, x, y); class C extends Thread myCanvas a;int steps;int x;C(myCanvas b,int s

23、ize) a=b;steps=size;x=0; public void run() while(true) x=x+steps; if (xa.getWidth() x=0; a.repaint(); a.paint(a.getGraphics(),x,50); trysleep(10); catch(InterruptedException e),2019/11/6,34,线程间的通信,1. 线程间的通信可以用管道流,. 创建管道流: PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOu

24、tputStream(pis); 或: PipedOutputStream pos=new PipedOutputStream(); PipedInputStream pis=new PipedInputStream(pos);,2019/11/6,35,管道流不能直 接读写PrintStream p = new PrintStream( pos ); p.println(“hello”); DataInputStream d=new DataInputStream(pis); d.readLine(); 2. 通过一个中间类来传递信息.,2019/11/6,36,管道流可以连接两个线程间的通

25、信 两个线程在运行,一个往外输出信息,一个读入信息. 将一个写线程的输出通过管道流定义为读线程的输入. outStream = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new Writer( outStream ).start(); new Reader( inStream ).start();,2019/11/6,37,主类Pipethread,辅类Writer 线 程 类,辅类 Reader 线 程 类,管 道 流,将数据写 到输出流,从流中读数据,输入流,作为参数传给Writer Write

26、r( outStream ),2019/11/6,38,7.4 多线程问题-线程间的通信,.,import java.io.*;public class Pipethread public static void main(String args) Pipethread thisPipe = new Pipethread(); thisPipe.process(); public void process() PipedInputStream inStream; PipedOutputStream outStream;PrintStream printOut;try outStream = n

27、ew PipedOutputStream();inStream = new PipedInputStream(outStream);new Writer( outStream ).start()new Reader( inStream ).start(); catch( IOException e ) ,2019/11/6,39,7.4 多线程问题-线程间的通信,class Reader extends Thread private PipedInputStream inStream;public Reader(PipedInputStream i)inStream=i;public void

28、 run() String line; DataInputStream d; boolean reading = true;d = new DataInputStream( inStream );while(reading ,2019/11/6,40,7.4 多线程问题-线程间的通信,.,class Writer extends Thread private PipedOutputStream outStream;private String messages= “Monday“,“Tuesday“,“Wednsday“,“Thursday“,“Friday :“,“Saturday:“,“S

29、unday :“;public Writer(PipedOutputStream o) outStream = o; public void run() PrintStream p = new PrintStream( outStream );for (int i = 0; i messages.length;i+) p.println(messagesi);p.flush();System.out.println(“WrIte:“ + messagesi ); tryThread.sleep(4000);catch(InterruptedException e);p.close(); p =

30、 null; ,2019/11/6,41,结果可能是:,WrIte:Monday Read: Monday WrIte:Tuesday Read: Tuesday Read: Wednsday WrIte:Wednsday Read: Thursday WrIte:Thursday Read: Friday : WrIte:Friday : WrIte:Saturday: Read: Saturday: Read: Sunday : WrIte:Sunday :,资源协调,2019/11/6,42,2019/11/6,43,资源协调,2019/11/6,44,对共享对象的访问必须同步,叫做条件

31、变量. Java语言允许通过监视器(有的参考书称其为管程)使用条件变量实现线程同步. 监视器阻止两个线程同时访问同一个条件变量.它如同锁一样作用在数据上. 线程1进入withdrawal方法时,获得监视器(加锁);当线程1的方法执行完毕返回时,释放监视器(开锁),线程2的withdrawal方能进入.,2019/11/6,45,用synchronized来标识的区域或方法即为监视器监视的部分。 一个类或一个对象有一个监视器,如果一个程序内有两个方法使用synchronized标志,则他们在一个监视器管理之下.一般情况下,只在方法的层次上使用关键区,2019/11/6,46,此处给出的例子演示两

32、个线程在同步限制下工作的情况. class Account statics int balance=1000;statics int expense=0;public synchronized void withdrawl(int amount) if (amount=balance) balance-=amount;expense+=amount;else System.out.println(“bounced: “+amount); ,实例范围同步方法 publicd class syncTest synchronized void aMethod() /需要同步使用的代码 synchro

33、nized aMethod()可以防止多个线程同时访问这个对象实例的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。,2019/11/6,47,实例范围同步区块 publicd class syncTest void aMethod() /无需同步使用的代码 synchronized(this) /需要同步使用的代码块 除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块

34、的资源实行互斥访问。用法是: synchronized(this)/*区块*/,它的作用域是当前对象。,2019/11/6,48,类范围 在类范围内使用synchronized也有同步方法和同步区块两种形式: 类范围同步方法 publicd class syncTest synchronized static void aMethod() /需要在类范围同步使用的代码 ,2019/11/6,49,synchronized static aStaticMethod防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。也就是说在一个JVM中,同

35、一时间最多有一个该类的静态同步方法在执行。这样的方法可以应用到多线程的同步中,实现各线程直接的数据共享和互动,2019/11/6,50,类范围同步区块 publicd class syncTest static void aMethod() /无需同步使用的代码 synchronized (syncTest.class) /需要在类范围同步使用的代码 类范围同步区块功能与类范围同步方法相同,只是对一个区块的代码的同步。用法是:在static 方法内加同步区块:sychronized (类名.class) /*区块*/。,2019/11/6,51,synchronized关键字是不能继承的,也就

36、是说,基类的方法synchronized f() 在继承类中并不自动是synchronized f(),而是变成了f()。继承类需要你显式的指定它的某个方法为synchronized方法;,2019/11/6,52,2019/11/6,53,2. 等待同步数据,可能出现的问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到 消费者比生产者快时,消费者取相同的数据. notify()和wait ()方法用来协调读取的关系. notify()和wait ()都只能从同步方法中的调用.,2019/11/6,54,notify的作用是唤醒正在等待同一个监视器的线程. wait的作用是让当前线程等待

37、 信息版例子 read()方法在读信息之前先等待,直到信息可读,读完后通知要写的线程. write()方法在写信息之前先等待,直到信息被取走,写完后通知要读的进程.,2019/11/6,55,writer,reader,aaaa,bbbbb,cccc,aaaa,aaaa,aaaa,aaaa,aaaa,aaaa,bbbbb,cccc,cccc,cccc,cccc,bbbbb,cccc,2019/11/6,56,public class WaitNotifyDemo public static void main(String args) MessageBoard m = new MessageB

38、oard();Reader readfrom_m = new Reader(m);Writer writeto_m=new Writer(m);writeto_m.start();readfrom_m.start(); ,2019/11/6,57,7.3 多线程问题-资源协调,class MessageBoard private String message; private boolean ready = false;public synchronized String read() while (ready = false) try wait(); catch (InterruptedEx

39、ception e) ready = false; notify(); return message;public synchronized void write(String s) while (ready = true) try wait(); catch (InterruptedException e) message = s;System.out.println(“Boad Got:“+s); ready = true; notify(); ,2019/11/6,58,7.3 多线程问题-资源协调,class Reader extends Thread private MessageB

40、oard mBoard;public Reader(MessageBoard m) mBoard = m; public void run() String s = “ “;boolean reading = true;while( reading )s = mBoard.read();System.out.println(“Reader read: “ + s);if( s.equals(“logoff“) ) reading = false; System.out.println(“Finished: 10 seconds.“);try sleep( 10000 ); catch (Int

41、erruptedException e) ,2019/11/6,59,7.3 多线程问题-资源协调,class Writer extends Thread private MessageBoard mBoard;private String messages = “Monday :-“,“,“Sunday : -“;public Writer(MessageBoard m) mBoard = m; public void run() for (int i = 0; i messages.length; i+) System.out.println(“Writer wrote:“ + messa

42、gesi );mBoard.write(messages i ); try sleep(int)(Math.random() * 100); catch (InterruptedException e) System.out.println(“Writer wrote:“ + “logoff“);mBoard.write(“logoff“); ,notifyAll()让等待某个对象K的所有线程离开阻塞状态, notify()随机地选取等待某个对象K的线程,让它离开阻塞状态 sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其

43、它线程可能正在运行而且没有被调度为放弃执行,除非: (a)“醒来”的线程具有更高的优先级 (b)正在运行的线程因为其它原因而阻塞,2019/11/6,60,waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常,2019/11/6,61,2019/11/6,62,多线程问题-资源的协调和锁定 1. 死

44、锁问题如果你持有一个锁并试图获取另一个锁时,就有死锁的危险. 解决死锁问题的方法:给条件变量施加排序,2019/11/6,63,多线程问题-daemon线程,什么是daemon(守护)? 在客户/服务器模式下,服务器的作用是等待用户发来请求,并按请求完成客户的工作守护线程是为其它线程提供服务的线程 守护线程一般应该是一个独立的线程,它的run()方法是一个无限循环. 守护线程与其它线程的区别是,如果守护线程是唯一运行着的线程,程序会自动退出,客户端,服务器端,request,daemon,2019/11/6,64,调用isDaemon(),可调查一个线程是不是一个Daemon setDaemo

45、n()打开或者关闭一个线程的Daemon状态 如果是一个Daemon线程,那么它创建的任何线程也会自动具备Daemon属性。,2019/11/6,65,小结,1. 实现线程有两种方法: 实现Ruannable接口 继承Thread类 2. 在小应用中通常在start中创建线程 3.当新线程被启动时,java调用该线程的run方法,它是Thread的核心. 4. 线程由四个状态:新生,运行,暂停,死亡,2019/11/6,66,5. 两个或多个线程竞争资源时,需要用同步的方法协调资源. 6. 多个线程执行时,要用到同步方法,即使用 synchronized的关键字设定同步区 7. wait和notify起协调作用 8. 守护进程的特点是当程序中只剩它自己时,会自动中止.,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报