第7章 多线程 北京大学计算机系 代亚非.

Slides:



Advertisements
Similar presentations
Java 程序设计 第 8 章 多线程. 第 8 章 Java 的多线程 8.1 线程及其创建 Java 中的线程 Java 程序通过流控制来执行程序流,程序中单个顺序的流 控制称为线程, 多线程则指的是在单个程序中可以同时运行 多个不同的线程执行不同的任务。 单个程序内部也可以在同一时刻进行多种运算。
Advertisements

Java 程序分类 Java Application :是完整程序,需要独立的解 释器解释运行;以 “.java” 为后缀的文件,以 main() 方法作为程序入口,由 java 编译器编译生 成字节码,由 Java 解释器加载执行字节码。 Java Applet 没有 main() 方法作为程序入口,是嵌在.
面向侧面的程序设计 方林博士 本文下载地址:
第四章 类、对象和接口.
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
第七章 多线程处理 线程的互斥 线程的同步 死锁问题.
讓你的程式具有多工(Multitasking) 及多重處理(Multiprocessing)的能力
檔案處理.
Java Programming Spring, 2010
Java程序设计教程 第一讲 Java概述.
四資二甲 第三週作業 物件導向程式設計.
第十五章 网络编程.
设计模式可以帮助我们改善系统的设计,增强 系统的健壮性、可扩展性,为以后铺平道路。
第11章 Java多媒体技术.
第二章 JAVA语言基础.
第二部分 Java语言基础篇 第4章 Java语言与面向对象 (之一).
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第三章 控制结构.
第九章 字符串.
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
Java语言程序设计 清华大学出版社 第9章 网络通信.
Ch07 Java Applets 物件導向系統實務.
Java语言程序设计 第七部分 多线程.
Java基础 JavaSE异常.
Multithread 多執行緒 I/O Lecturer:楊昌樺.
C#程序设计 c# programming 多线程 C#程序设计课程组.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第五章 继承、接口与范型.
程式設計實作.
第2章回顾 标识符:不用记,动手 关键字:if, else, switch, for, while, do, break, continue, void, …… 局部变量和成员变量 ①变量作用域 ②内存布局 基本数据类型 ①4类8种 ②互相转换 流程控制语句 ①分支 if……else, switch.
2018/12/3 面向对象与多线程综合实验-网络编程 教师:段鹏飞.
Java语言程序设计 第五部分 Java异常处理.
王豐緒 銘傳大學資訊工程學系 問題:JAVA 物件檔輸出入.
辅导课程六.
第10章 Java的线程处理 10.1 线程的基本概念 10.2 线程的属性 10.3 线程组 10.4 多线程程序的开发.
临界区软件互斥软件实现算法.
第一次课后作业 1. C/C++/Java 哪些值不是头等程序对象 2. C/C++/Java 哪些机制采用的是动态束定
9.1 程式偵錯 9.2 捕捉例外 9.3 自行拋出例外 9.4 自定例外類別 9.5 多執行緒
3.1 数据类型 3.2 标识符与关键字 3.3 常量 3.4 变量 3.5 运算符与表达式 3.6 一个编程实例
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
异常及处理.
临界区软件互斥软件实现算法 主讲教师:夏莹杰
C/C++/Java 哪些值不是头等程序对象
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: QQ:
Java语言程序设计 清华大学出版社 第8章 输入输出流(1).
Multithread 多執行緒 以GUI為例了解物件以及Event
第7章 Java 的多线程机制.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
C语言程序设计 主讲教师:陆幼利.
第二章Java基本程序设计.
第二章 Java基本语法 讲师:复凡.
Java程式初體驗大綱 大綱 在學程式之前及本書常用名詞解釋 Hello Java!程式 在Dos下編譯、執行程式
信号量(Semaphore).
第二章 Java语法基础.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第八章 线程.
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
辅导课程十五.
第二章 Java基本语法 讲师:复凡.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
PPT注意事项: 当前PPT课件文件必须和提供的源代码文件夹“代码”在同一目录中即不要移动文件夹“代码”的默认位置。
第2章 Java语言基础.
判斷(選擇性敘述) if if else else if 條件運算子.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
第二章 Java基础语法 北京传智播客教育
第二章 Java基本语法 讲师:复凡.
Summary
Presentation transcript:

第7章 多线程 北京大学计算机系 代亚非

第7章 多线程 7.1 多线程基本概念 7.2 创建线程的方式 7.3 线程的挂起与唤醒 7.4 多线程问题 7.5 小结

7.1 多线程基本概念 多线程的任务 传统的进程 文件 各种系统资源 输入输出装置 文件 各种系统资源 输入输出装置 数据区段 数据区段 7.1 多线程基本概念 文件 各种系统资源 输入输出装置 文件 各种系统资源 输入输出装置 数据区段 数据区段 程序区段 程序区段 同时有数个地方在执行 只有一个地方在执行 多线程的任务 传统的进程

7.1 多线程基本概念 多线程的优势: 减轻编写交互频繁、涉及面多的程序的困难. 程序的吞吐量会得到改善. 7.1 多线程基本概念 多线程的优势: 减轻编写交互频繁、涉及面多的程序的困难. 程序的吞吐量会得到改善. 由多个处理器的系统,可以并发运行不同的线程.(否则,任何时刻只有一个线程在运行)

7.1 多线程基本概念 线程与进程的区别: 多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响. 线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小。

7.1 多线程基本概念 对线程的综合支持是Java技术的一个重要特色.它提供了thread类、监视器和条件变量的技术. 7.1 多线程基本概念 对线程的综合支持是Java技术的一个重要特色.它提供了thread类、监视器和条件变量的技术. 虽然Macintosh,Windows NT,Windows 9等操作系统支持多线程,但若要用C或C++编写多线程程序是十分困难的,因为它们对数据同步的支持不充分.

7.2 创建线程的方式 1. public class mythread extends Applet implements Runnable (小应用或已经是某个类的子类时) 2. 继承类Thread public class mythread extends Thread 3. 上述两种方法中都可用类Thread产生线程的对象 Thread newthread; 4. 创建并启动线程 newthread=new Thread(this); newthread.start();

7.2 创建线程的方式 5. run方法是运行线程的主体,启动线程时,由java直接调用 public void run() 7.2 创建线程的方式 5. run方法是运行线程的主体,启动线程时,由java直接调用 public void run() 6.停止线程,由小应用程序的stop调用线程的stop newthread.stop() 7 sleep方法的作用,暂停线程的执行,让其它线程得到机会,sleep要丢出异常,必须抓住. Try{sleep(100)}catch(InterruptedException e){} 例:小应用程序中不用Runnable接口仍然可以使用线程(不调用主类的方法和调用主类的方法)

7.2 创建线程的方式 import java.applet.*; public class thread extends Applet 7.2 创建线程的方式 import java.applet.*; public class thread extends Applet { mythread t1=new mythread(); public init() { t1.start();} class mythread extends Thread { public void run() { for (int i=0;i<4;i++) System.out.println( “”+i); { try{sleep(400); } catch(InteruptedException e){ } }

7.2 创建线程的方式 public class mainclass extends Applet { 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 { mainclass a; C(mainclass b) { a=b; } public void run() { while(true){ a.repaint(); try{sleep(400);} catch(InterruptedException e){} }} 7.2 创建线程的方式

7.2 创建线程的方式 8.其它常用的方法 isAlive :判断线程目前是否正在执行状态中 7.2 创建线程的方式 8.其它常用的方法 isAlive :判断线程目前是否正在执行状态中 if(newthread.isAlive()) newthread.stop(); resume:要求被暂停得线程继续执行 suspend:暂停线程的执行 join:等待线程执行完毕 thatThread.join();被等待的那个线程不结束,当前线程就一直等待. yield:将执行的权力交给其它线程,自己到队列的最后等待.

7.2 创建线程的方式 9.线程的优先权 某一时刻只有一个线程在执行,调度策略为固定优先级调度. 7.2 创建线程的方式 9.线程的优先权 某一时刻只有一个线程在执行,调度策略为固定优先级调度. newthread.setPriority(Thread.MIN_PRIORITY) 级别有:MIN-PRIORITY NOM_PRIORITY MAX-PRIORITY 10. 自私的线程:有很高的优先权的线程,不主动睡眠或让出处理器控制权.

7.2 创建线程的方式 11. 线程的状态 new Thread() New Thread Runnable start() 7.2 创建线程的方式 11. 线程的状态 new Thread() New Thread Runnable start() Not Runnable stop() Dead yield() stop() or run()exit . suspend() sleep() wait() resume()

7.2 创建线程的方式 当一个线程执行完所有语句后就自动终止,调用线程的stop()方法,也可以强制终止线程。 7.2 创建线程的方式 当一个线程执行完所有语句后就自动终止,调用线程的stop()方法,也可以强制终止线程。 如果希望线程正常终止,可采用标记来使线程中的run()方法退出。

7.2 创建线程的方式 public class Xyz implements Runnable 7.2 创建线程的方式 public class Xyz implements Runnable { private boolean timeToQuit=false; public void run() { while (!timeToQuit) {…..} //clean up before run() ends; } public void stopRunning() { timeToQuit=true;}

7.2 创建线程的方式 public class ControlThread { private Runnable r=new Xyz(); 7.2 创建线程的方式 public class ControlThread { private Runnable r=new Xyz(); private Thread t=new Thread(r); public void startThread() { t.start(); } publi void stopThread() { r.stopRunning();} }

7.3 线程的挂起与唤醒 暂停线程的执行等待条件满足再执行. 下面的例子显示线程的挂起和唤醒 小应用程序第一次开始时,线程被启动 7.3 线程的挂起与唤醒 暂停线程的执行等待条件满足再执行. 下面的例子显示线程的挂起和唤醒 小应用程序第一次开始时,线程被启动 浏览器改变页面时,小应用程序的stop()方法被调用,线程被挂起. 浏览器回到原来的页面时,线程被唤醒.

7.3 线程的挂起与唤醒 public void start() { if (mythread==null) 7.3 线程的挂起与唤醒 public void start() { if (mythread==null) {mythread=new Thread(); mythread.start();} else { mythread.resume();} } public void run() { while(true){ try{sleep(100);} catch(InterruptedException e) {}} public void stop() { mythread.suspend(); }.

7.4 多线程问题---执行的顺序 多个线程运行时,调度策略为固定优先级调度.级别相同时,由操作系统按时间片来分配 7.4 多线程问题---执行的顺序 多个线程运行时,调度策略为固定优先级调度.级别相同时,由操作系统按时间片来分配 下面给出的例子中,共运行三个线程,它们做同样的事, 每次打印循环次数和自己的序列号,运行结果表明,它们并不是连续运行的. 在上例中如果给某个线程赋予较高的优先权,则发现这个进程垄断控制权 thread.setPriority(Thread.MAX_PRIORITY) thread\multithread.class--f1.bat thread\Priority.class---f2.bat

7.3 多线程问题 //多个进程运行时执行顺序是交叉的 class multithread extends Thread { int threadNum; public static void main(String args[]) { multithread array[]=new multithread[3]; for (int i=0;i<3;i++) array[i]=new multithread(i); for (int i=0;i<3;i++) array[i].start(); } multithread(int SerialNum) { super(); threadNum=SerialNum; } public void run() { for(int j=0;j<5;j++) System.out.println(“<"+j+"> +MySerialNum); System.out.println("thread "+threadNum+ "bye.");}} 7.3 多线程问题

7.4 多线程问题---如何写多线程 1.分别定义不同的线程类,在各自的run方法中定义线程的工作 7.4 多线程问题---如何写多线程 1.分别定义不同的线程类,在各自的run方法中定义线程的工作 class mythread1 extends Thread { public void run{….} } class mythread2 extends Thread 2. 在主类中实例化各线程类,并启动线程. public class demo extends Applet { public void init() { mythread t1=new mythread1(); mythread t2=new mythread2(); t1.start(); t2.start();} }

7.4 多线程问题---如何写多线程 练习:将窗口分为上下两个区,分别运行两个线程,一个在上面的区域中显示由右向左游动的字符串,另一个在下面的区域从左向右游动的字符串. 方法一: 一个线程,在paint方法中使用两个输出字符串的语句 public void paint(Graphics g) { if y1<0 y1=200 else y1=y1-10; if y2>200 y2=0 else y2=y2+10; g.drawString(“hello, Java!”,20,y1,); g.drawString(“hello, Java!”,40,y2,); }

7.4 多线程问题---如何写多线程 方法二:定义两个类,运行各自的线程,各自有自己的paint()方法. 7.4 多线程问题---如何写多线程 方法二:定义两个类,运行各自的线程,各自有自己的paint()方法. 注意: 两个小应用程序必须是panel类或者是canvas类,将小应用的区域分成两块,否则不能运行paint语句.

7.4 多线程问题---线程间的通信 1. 线程间的通信可以用管道流,. 创建管道流: 7.4 多线程问题---线程间的通信 1. 线程间的通信可以用管道流,. 创建管道流: PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOutputStream(pis); 或: PipedOutputStream pos=new PipedOutputStream(); PipedInputStream pis=new PipedInputStream(pos); 线程1 PipedOutputStream PipedInputStream 输出流outStream 输入流inStream 线程2

7.4 多线程问题---线程间的通信 管道流不能直 接读写 PrintStream p = new PrintStream( pos ); 7.4 多线程问题---线程间的通信 管道流不能直 接读写 PrintStream p = new PrintStream( pos ); p.println(“hello”); DataInputStream d=new DataInputStream(pis); d.readLine(); 2. 通过一个中间类来传递信息. printStream DataInputStream 线程2 线程1 中间类m s m.write(s) s=m.read() write() read()

7.4 多线程问题--线程间的通信 管道流可以连接两个线程间的通信 下面的例子里有两个线程在运行,一个往外输出信息,一个读入信息. 将一个写线程的输出通过管道流定义为读线程的输入. outStream = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new Writer( outStream ).start(); new Reader( inStream ).start();

7.4 多线程问题--线程间的通信 (thread\Pipethread.class--f3.bat) 主类Pipethread 作为参数传给Writer Writer( outStream ) 辅类Writer 线 程 类 管 道 流 辅类 Reader 线 程 类 将数据写 到输出流 输入流 从流中读数据

7.4 多线程问题--线程间的通信 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 = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new Writer( outStream ).start(); new Reader( inStream ).start(); }catch( IOException e ){ } } 7.4 多线程问题--线程间的通信 .

7.4 多线程问题---线程间的通信 class Reader extends Thread { private PipedInputStream inStream;//从中读数据 public Reader(PipedInputStream i) { inStream = i; } public void run() { String line; DataInputStream d; boolean reading = true; try{ d = new DataInputStream( inStream ); while( reading && d != null){ try{line = d.readLine(); if( line != null ){ System.out.println( ”Read: " + line ); } else reading = false; }catch( IOException e){ } } catch( IOException e ){ System.exit(0); } try{ Thread.sleep( 4000 );} catch( InterruptedException e ){}}} 7.4 多线程问题---线程间的通信

7.4 多线程问题--线程间的通信 class Writer extends Thread { private PipedOutputStream outStream;//将数据输出 private String messages[ ]= { "Monday", "Tuesday ", "Wednsday", "Thursday","Friday :", "Saturday:","Sunday :"}; public Writer(PipedOutputStream o) { outStream = o; } public void run() { PrintStream p = new PrintStream( outStream ); for (int i = 0; i < messages.length; i++) { p.println(messages[ i ]); p.flush(); System.out.println("WrIte:" + messages[i] ); } p.close(); p = null; }} 7.4 多线程问题--线程间的通信 .

7.3 多线程问题---资源协调 1. 数据的完整性 变量 余额 withdrwal() 透支 线程1 取过来 资源 加1后送回去 线程2 线程10 资源 取过来 加1后送回去 withdrwal() 透支 余额 变量

7.3 多线程问题---资源协调 对共享对象的访问必须同步,叫做条件变量. Java语言允许通过监视器(有的参考书称其为管程)使用条件变量实现线程同步. 监视器阻止两个线程同时访问同一个条件变量.它的如同锁一样作用在数据上. 线程1进入withdrawal方法时,获得监视器(加锁);当线程1的方法执行完毕返回时,释放监视器(开锁),线程2的withdrawal方能进入. withdrawal() 线程1 监视器 线程2

7.3 多线程问题---资源协调 用synchronized来标识的区域或方法即为监视器监视的部分。 一般情况下,只在方法的层次上使用关键区 read write 监 视 器 线程1 线程2

7.3 多线程问题---资源协调 此处给出的例子演示两个线程在同步限制下工作的情况. class Account { statics int balance=1000; //为什么用static? statics int expense=0; public synchronized void withdrawl(int amount) { if (amount<=balance) { balance-=amount; expense+=amount;} else { System.out.println(“bounced: “+amount);} }

7.3 多线程问题---资源协调 2. 等待同步数据 可能出现的问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到 共享对象 write read 可能出现的问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到 消费者比生产者快时,消费者取相同的数据. notify()和wait ()方法用来协调读取的关系. notify()和wait ()都只能从同步方法中的调用.

7.3 多线程问题---资源协调 notify的作用是唤醒正在等待同一个监视器的线程. wait的作用是让当前线程等待 信息版例子 read()方法在读信息之前先等待,直到信息可读,读完后通知要写的线程. write()方法在写信息之前先等待,直到信息被取走,写完后通知要读的进程. DemoWait.class--->f4.bat

7.3 多线程问题---资源协调 writer reader aaaa aaaa aaaa aaaa aaaa aaaa aaaa bbbbb bbbbb bbbbb cccc cccc cccc cccc cccc cccc

7.3 多线程问题---资源协调 class WaitNotifyDemo { public static void main(String[] args) { { MessageBoard m = new MessageBoard(); Reader readfrom_m = new Reader(m); Writer writeto_m=new Writer(m); readfrom_m.start(); writeto_m.start(); }

7.3 多线程问题---资源协调 class MessageBoard { { private String message; private boolean ready = false;(信号灯) public synchronized String read() { while (ready == false) { try { wait(); } catch (InterruptedException e) { } } ready = false; notify(); //起始状态先写后读 return message; } public synchronized void write(String s) { while (ready == true) { try { wait(); } catch (InterruptedException e) { } } message = s; ready = true; notify(); }} 7.3 多线程问题---资源协调

7.3 多线程问题---资源协调 class Reader extends Thread { private MessageBoard 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 (InterruptedException e) { } } } 7.3 多线程问题---资源协调

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++) { mBoard.write(messages[ i ]); System.out.println("Writer wrote:" + messages[i] ); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } mBoard.write("logoff"); } } 7.3 多线程问题---资源协调

7.3 多线程问题---资源协调 多线成问题---资源的协调和锁定 1. 死锁问题 如果你的持有一个锁并试图获取另一个锁时,就有死锁的危险. 解决死锁问题的方法:给条件变量施加排序 线程2 pen 线程1 note 把“pen”给我,我 才能给你“note” 把“note”给我,我 才能给你“pen”

7.3 多线程问题---daemon线程 什么是daemon(守护)? 在客户/服务器模式下,服务器的作用是等待用户发来请求,并按请求完成客户的工作 守护线程是为其它线程提供服务的线程 守护线程一般应该是一个独立的线程,它的run()方法是一个无限循环. 守护线程与其它线程的区别是,如果守护线程是唯一运行着的线程,程序会自动退出 request 服务器端 客户端 daemon

7.4 小结 1. 实现线程有两种方法: 实现Ruannable接口 继承Thread类 2. 在小应用中通常在start中创建线程 3.当新线程被启动时,java调用该线程的run方 法,它是Thread的核心. 4. 线程由四个状态:新生,运行,暂停,死亡 5. 线程间的通信方式由三种:完全共享数据,通过监视器,通过join.

7.4 小结 6. 两个或多个线程竞争资源时,需要用同步的方法协调资源. 7. 多个线程执行时,要用到同步方法,即使用 synchronized的关键字设定同步区 8. wait和notify起协调作用 9. 守护进程的特点是当程序中制胜它自己时,会自动中止.

作业 创建两个线程的实例,分别将一个数组从小大大和从达到小排列.输出结果.