Multithread 多執行緒 I/O Lecturer:曾學文.

Slides:



Advertisements
Similar presentations
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
Advertisements

第一單元 建立java 程式.
项目6 通用堆栈.
計算機程式語言實習課.
檔案處理.
Java程序设计教程 第一讲 Java概述.
Java的程式架構與基本觀念 Java語言的歷史 Java程式的開發環境 Java程式的架構 輸出與輸入物件之使用 工具使用方法介紹
第五章 字符串.
視窗程式設計 2. 視窗版面配置 Chih Hung Wang Reference:
第11章 Java多媒体技术.
第二章 JAVA语言基础.
创意源自激情,技术成就梦想 畅翼创新俱乐部 2012年春俱乐部第三次技术培训 赵程.
Ch08 基本輸出入與檔案處理 物件導向系統實務.
第9章 例外與檔案處理 9-4 檔案與資料夾處理 9-5 Java的輸入/輸出串流 9-6 檔案的讀取與寫入.
Chin-Yi Tsai Java Chin-Yi Tsai
第7章 输入输出处理.
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
程式語言的基礎 Input Output Program 世代 程式語言 第一世代 Machine language 第二世代
第5章 面向对象程序设计 本章要点 5.1 面向对象程序设计概述 5.2 Java语言的面向对象程序设计 5.3 方法的使用和对象数组
API设计实例分析 通用IO API.
Java语言程序设计 清华大学出版社 第9章 网络通信.
例外處理(Exception Handling)
Java 的例外與輸入出檔案處理 Jing Ming Huang.
Java 第28讲:建立删除文件 主讲教师:李焱 讲师.
Java语言程序设计 第七部分 多线程.
2018/11/20 第一章 Java概述 武汉大学计算机学院计算机应用系 2018/11/20 14:33.
程式敘述執行順序的轉移 控制與重複、方法 Lecturer:曾學文.
Multithread 多執行緒 I/O Lecturer:楊昌樺.
JAVA 程式設計與資料結構 第六章 輸出與輸入.
第十三章 文件和注册表操作.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第五章 继承、接口与范型.
程式設計實作.
第四章 基本輸出入 Java應用程式的輸出入介面有三種,分別是命令提示字元視窗、AWT元件、及Swing元件。本單元先介紹命令提示字元視窗,AWT請看第16、17章,Swing請看第20章。 輸入 輸出.
抽象类 File类 String类 StringBuffer类
Java程序设计 第18章 二进制I/O.
王豐緒 銘傳大學資訊工程學系 問題:JAVA 二元檔輸出入.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第九章 输入/输出流.
2018/12/3 面向对象与多线程综合实验-网络编程 教师:段鹏飞.
類別(class) 類別class與物件object.
SQL Stored Procedure SQL 預存程序.
Java语言程序设计 第五部分 Java异常处理.
第七章 输入/输出 标准输入输出 流式I/O基础 文件 随机存取文件 对象输入/输出流.
王豐緒 銘傳大學資訊工程學系 問題:JAVA 物件檔輸出入.
第10章 Java的线程处理 10.1 线程的基本概念 10.2 线程的属性 10.3 线程组 10.4 多线程程序的开发.
第一次课后作业 1. C/C++/Java 哪些值不是头等程序对象 2. C/C++/Java 哪些机制采用的是动态束定
例外處理與 物件序列化(Exception Handling and Serialization of Objects)
9.1 程式偵錯 9.2 捕捉例外 9.3 自行拋出例外 9.4 自定例外類別 9.5 多執行緒
Java 程式設計 講師:FrankLin.
异常及处理.
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
第五讲 JSP中的文件操作(1) 教学目的 本讲主要讲述JSP中使用Java输入、输出流实现文件的读写 操作 。 知识要点
第一單元 建立java 程式.
4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: QQ:
Multithread 多執行緒 以GUI為例了解物件以及Event
《JAVA程序设计》 语音答疑 辅导老师:高旻.
第二章Java基本程序设计.
第二章 Java基本语法 讲师:复凡.
Interfaces and Packages
File Input and Output Chap. 11: 施威銘的書 Chap. 7: K&R.
第二章 Java语法基础.
第二章 Java基本语法 讲师:复凡.
助教:廖啟盛 JAVA Socket(UDP) 助教:廖啟盛
第2章 Java语言基础.
Chapter 4 Multi-Threads (多執行緒).
第二章 Java基础语法 北京传智播客教育
第二章 Java基本语法 讲师:复凡.
Summary
方法(Method) 函數.
InputStreamReader Console Scanner
Presentation transcript:

Multithread 多執行緒 I/O Lecturer:曾學文

Important Features of Java 何謂多工 (Multi-tasking) 例如,撰寫網路程式,模擬程式。 Java 利用 “執行緒” (Thread) 來實作多工 可將一個Process分成數份, 讓各部份能同時被執行。

Process and Thread Process - 正在執行的應用程式 不同的行程會對應到不同的 系統資源 CPU時間 Multithread的概念特別針對CPU時間的分配 暫時閒置的CPU時間,用在執行應用程式的其他工作上 語法不難,難在掌控 執行先後順序 資源維護

執行緒的生命週期 Blocked start() Runnable Running yield() notify(), I/O unblock sleep(), wait(), , I/O block start() Runnable Running yield()

設計背景 雖然說一次可以處理多個執行緒 不過在同一個時間點真正執行的還是只有一個 (例外:多CPU系統可以執行多個) 處理多個執行緒時 一次只有一個執行緒在執行(Running) 其他執行緒在Runnable區塊中等待 執行先後順序會依照執行緒的優先權來判定 沒執行的在Runnable區塊中等待下一次優先權的判定

Thread類別 java.lang.Thread 提供的基本方法 public class Thread extends Object implements Runnable 提供的基本方法 static yield() 讓目前running的暫停, 讓runnable的擇一跑 static sleep() 讓目前running的睡一個設定的時間 start() 啟動, 之後JVM可啟動該thread的run() setPriority() setPriority(MAX_PRIORITY):給最大優先權 setPriority(MIN_PRIORITY):給最小優先權 setPriority(NORM_PRIORITY):預設的優先權

簡單程式範例 (MyThread.java) public class MyThread extends Thread{ MyThread(String n) { super(n); } public void run() String tname = super.getName(); try for(int i = 1; i<=5000;i++) System.out.println(tname+" "+i+" "+Math.random()); catch(Exception e) System.out.println("error"); class TestThread { public static void main(String[] args) MyThread t1 = new MyThread("t1"); MyThread t2 = new MyThread("t2"); t1.start(); t2.start(); } thread t1, t2 各執行5000次迴圈,在各個電腦產生的執行順序也會因為各個電腦當時的CPU效能而有所不同

說明 新的執行緒物件(new MyThread) 經由start()方法進入Runnable 區準備執行 排程後將選出來的執行緒丟入Running區執行 此時會觸發執行緒run()方法,執行實作內容(寫在run()內的程式碼) 若執行緒未執行完成(例如取得的CPU時間已到卻還沒完成工作,或是程式呼叫了特定的方法) ,或是執行wait(),將會觸發Blocking event並進入Blocked區 被封鎖的執行緒解除封鎖(Unblocked)或者是或別的程式中呼叫了notify()方法之後,將再進入Runnable pool中等待下一次執行 若程式中呼叫了yield()方法(讓與),則是將執行權先給其他執行緒執行,不過其本身仍然還是在Runnable中

不能多重繼承時 (MyThread2.java) public class MyThread2 implements Runnable { int i; public void run() i = 0; while (true) System.out.println(Thread.currentThread().getName() + " " + (++i) + " " +Math.random()); if ( i == 5000 ) break; } class TestThread2 { public static void main(String args[]) MyThread2 r = new MyThread2(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.setName(“t1"); t2.setName(“t2"); t1.start(); t2.start(); } 先宣告一個空的MyThread2類別物件r 建立t1, t2 執行緒物件實體,其對象為 MyThread2中的run()方法

如果執行緒間彼此有同步的考量 (MyThread3.java) public class MyThread3 implements Runnable{ static int max=0; public void run() { for(int i = 1; i<=5000;i++) int tmp=max; System.out.println(Thread.currentThread().getName()+" "+ ++tmp); max=tmp; } class TestThread3 { public static void main(String args[]) MyThread3 r = new MyThread3(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.setName("t1"); t2.setName("t2"); t1.start(); t2.start(); } 各把max拿來加5000次 最後卻不一定等於10000 而且每次都不一樣, why?

方法加 synchronized 保證 addMax()這個方法 只有同時間只有一個process可以執行 public class MyThread4 implements Runnable{ static int max=0; public void run() { for(int i = 1; i<=5000;i++) addMax(); } private synchronized void addMax() int tmp=max; System.out.println(Thread.currentThread().getName() + " " + ++tmp); max=tmp; 保證 addMax()這個方法 只有同時間只有一個process可以執行

Applet上有數個動畫 } public void run() { off_image = this.createImage(width,height); off_graphics =off_image.getGraphics(); off_graphics.setColor(getBackground()); while(running) cnt = (++cnt)%images.length; off_graphics.fillRect(0,0,width,height); off_graphics.drawImage(images[cnt],0,0,this); try { Thread.sleep(delay); } catch(Exception e) { break; repaint(); public void update(Graphics g){g.drawImage(off_image,0,0,this);} public void paint(Graphics g){update(g);} public void setRunning(boolean val){running=val;} class DBPicShower extends Panel implements Runnable { int cnt=-1; int delay; int width, height; Image[] images; boolean running; Image off_image; Graphics off_graphics; public DBPicShower(int fps, Image[] imgs, int w, int h){ delay =(fps<0)?100:(1000/fps); running = true; this.setSize(w,h); width =w; height = h; images = imgs;} public Dimension getPreerredSize(){return getMinimumSize();} public Dimension getMinimumSize(){return new Dimension(width,height);}

Applet上有數個動畫 this.setLayout(flowLayout1); images = new Image[10]; shower = new DBPicShower[4]; showerThread = new Thread[4]; for(int i=0;i<10;i++) {images[i]=this.getImage(getCodeBase(),"T"+(i+1)+".gif");} for(int i=0;i<4;i++) { shower[i] = new DBPicShower(20,images,500,500); showerThread[i] = new Thread(shower[i]); this.add(shower[i]); } //Component initialization private void jbInit() throws Exception { this.setLayout(flowLayout1 ); //Get Applet information public String getAppletInfo() { return "Applet Information"; //Get parameter info public String[][] getParameterInfo() { return null; public void start(){ {showerThread[i].start();} Applet上有數個動畫 public class Applet1 extends Applet { boolean isStandalone = false; String[] imgFile; Thread[] showerThread; DBPicShower[] shower; Image[] images; // VerticalFlowLayout verticalFlowLayout1 = new VerticalFlowLayout(); FlowLayout flowLayout1 = new FlowLayout(); //Get a parameter value public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } //Construct the applet public Applet1() { //Initialize the applet public void init() { try { jbInit(); catch(Exception e) { e.printStackTrace();

Your Turn 寫一個多執行緒程式,模擬三個人存同一個戶頭的錢,每次存1000圓,總共存10次 每次存完讓該Thread睡個幾毫秒 Thread.sleep((long)(Math.random()*10)); 這個方法需要處理exception,試用教過的例外處理 最後輸出的是隨機的存款出現的順序 確保最後出現的是三萬元 (可以每次顯示是誰存的,存多少,總額)

I/O Overview of I/O Streams Using the Streams File Streams Wrap Streams InputStreams Your Turn Standard in and out Streams Pipe Streams SequenceInputStream Filter Streams Random Access File

Overview of I/O Streams

Overview of I/O Streams 讀取與寫出資料的演算法: 讀取 寫出 開啟資料流 while 還有資料 讀取資料 關閉資料流 寫出資料 在 Java 中,處理 IO 必須要 import java.io 這個 package 根據資料型態(字元或位元),可以分成二類:

Overview of I/O Streams Character Streams 用來處理 16 位元資料,如:字元資料(unicode) Reader 和 Writer 是所有 character streams 的 abstract superclasses

Overview of I/O Streams Byte Streams 用來處理 8 位元資料,如:執行檔、圖檔和聲音檔 InputStream 和 OutputStream 是所有 byte streams 的 abstract superclasses

Overview of I/O Streams Understanding the IO Superclasses Reader 與 InputStream 有非常類似的 API,只是處理的資料型態不同,如: Reader 中的 methods int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) InputStream 中的 methods int read(byte buf[]) int read(byte buf[], int offset, int length)

Overview of I/O Streams Writer 與 OutputStream Writer 中的 methods int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) OutputStream 中的 methods int write(byte buf[]) int write(byte buf[], int offset, int length) 所以的 Streams 都一樣,在物件建立之後,就會自動開啟,而呼叫 close() 就可以關閉資料流

Using the Streams I/O 類型 資料流類別 說明 檔案(File) 功能在於存取檔案或檔案系統的內容 管線(Pipe) FileReader FileWriter FileInputStream FileOutputStream 功能在於存取檔案或檔案系統的內容 管線(Pipe) PipedReader PipedWriter PipedInputStream PipedOutputStream 將某個程式(或 Thread)的輸出導入另一個程式的輸入 串接(Concatenate) 未提供 SequenceInputStream 將多個 input stream 串接到同一個 input stream

Using the Streams I/O 類型 資料流類別 說明 緩衝(Buffer) 讀寫時為資料緩衝區,可以減少存取原始資料的次數 BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream 讀寫時為資料緩衝區,可以減少存取原始資料的次數 過濾(Filter) FilterReader FilterWriter FilterInputStream FilterOutputStream 這幾個類別都是 abstract class,定義了過濾讀寫資料的介面 物件序列化 (Object Serialization) 未提供 ObjectInputStream ObjectOutputStream 用來做物件序列化(Object Serialization)的動作

File 檔案與目錄之操作 在 Java 中建立 File 物件,就可以取得檔案的或資料夾的相關訊息,如:File f = new File(String); File() 建構元參數是檔案或是資料夾的路徑 例如: import java.io.*; File f = new File(“haha.txt”);

File File 的相關方法 public boolean isDirectory() public boolean isFile() 傳回目前 java.io.File 內所包含的這個名稱是否為一個資料夾 public boolean isFile() 傳回目前 java.io.File 內的名稱是否為一個檔案 public String[] list() 傳回目前資料夾內所包含的資料夾名稱及檔案名稱

檔案清單範例 Example: Dir.java import java.io.*; public class Dir { public static void main(String[] args) { String[] filenames; File f = new File(args[0]); if ( f.isDirectory() ) { filenames = f.list(); for(int i=0; i< filenames.length; i++) System.out.println(filenames[i]); } else System.out.println(f + "is not a directory");

顯示檔案資訊 相關方法 public boolean exists(): 檢查檔案是否存在 public boolean canRead(): 是否可讀 public boolean canWrite(): 是否可寫 public getName(): 傳回該檔案的名稱 public long length(): 傳回檔案大小 public long lastModified(): 傳回檔案修改時間 public getPath(): 取得該檔案所屬的資料夾名稱 public getParent(): 取得該檔案所屬的父資料夾名稱 public getAbsoluteFile(): 傳回該檔案的絕對路徑

顯示檔案資訊範例 Exmaple: FileInfo.java File f = new File(args[0]); if ( f.exists() ) { if ( f.isFile() ) System.out.print("File: "); else if(f.isDirectory()) System.out.print("Directory: "); System.out.println(f.getAbsoluteFile()); System.out.println("Length: " + f.length()); System.out.println("Readable: " + f.canRead()); System.out.println("Writable: " + f.canWrite()); } else System.out.println(f + " does not exist!");

更改檔案名稱 相關方法 public boolean renameTo(File dest) 功能:更改檔名 傳回值:true  成功,false  失敗

更改檔案名稱範例 Example: RenameFile.java File fs = new File(args[0]); File fd = new File(args[1]); if ( fs.exists() ) { if ( !fd.exists() ) { if (fs.renameTo(fd)) { System.out.println(fs.getName() + " --> " + fd.getName()); System.out.println("1 file(s) has been renamed!"); } else System.out.println("Target name already exists!"); System.out.println("Wrong source name!");

File 相關方法 刪除檔案 public boolean delete() 功能:刪除檔案 傳回值:true  刪除成功;false  失敗 建立資料夾 boolean mkdir() boolean mkdirs() 建立資料夾,成功傳回 true;失敗 false

建立資料夾範例 Example: MakeDir.java import java.io.*; public class MakeDir { public static void main(String[] args) { File dir = new File(args[0]); if ( !dir.exists() ) { boolean success = dir.mkdir(); // boolean success = dir.mkdirs(); System.out.println("Create "+dir+" is successed!!"); } else System.out.println(dir + " is already exist!!!");

FileReader / FileWriter 可利用 File 物件來當作 FileReader / FileWriter 的建構元參數 如: File inputFile = new File(“test.txt”); FileReader in = new FileReader(inputFile); 建立 FileReader 的物件之後可用 read() 來讀入 16-bit 字元 建立 FileWriter 的物件之後可用 write() 來寫出 16-bit 字元

FileReader public class Untitled1 { public Untitled1() { } public static void main(String[] args) throws IOException { Untitled1 untitled11 = new Untitled1(); String[] filenames; FileReader in = new FileReader("c:\\ip.txt"); int c; while ((c = in.read()) != -1) System.out.println((char)c); in.close();

FileWriter public class Untitled1 { public Untitled1() { } public static void main(String[] args) throws IOException { Untitled1 untitled11 = new Untitled1(); String[] filenames; FileReader in = new FileReader("c:\\ip.txt"); FileWriter out = new FileWriter("c:\\op.txt"); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close();

Wrap Streams Wrap Streams – 包裹 Stream 以一種 stream 類別包裹另一種 stream 類別的情形,這樣可以將各種不同資料流中好用的 methods 合併使用 在讀取資料時,可以利用 BufferedReader 將來源包裹(wrap)起來,如此一來便可以使用呼叫 BufferedReader 中提供的 readLine() 來讀入一整行的資料

How to Wrap a Stream 想計算檔案中的行數 查 class FileRead ->沒有這種功能 -> 自己寫??? 又查到 class BufferedReader中有 public String readLine() throws IOException 怎麼辦??->包裝FileReader使成Buffered 查BufferedReader的Constructor BufferedReader (Reader in)

Example public class Untitled1 { public Untitled1() { } public static void main(String[] args) throws IOException { Untitled1 untitled11 = new Untitled1(); String[] filenames; FileReader in = new FileReader("c:\\ip.txt"); BufferedReader br = new BufferedReader(in); String aline; int cnt=0; while ((aline = br.readLine())!=null ) { System.out.println(aline); cnt++; System.out.println(cnt); br.close();

Java讀寫檔案 BufferedReader 和 BufferedWriter 程式做 IO 動作時,使用 8K 左右大小之 Buffer 可得到最佳效能 BufferedReader 和 BufferedWriter 已經內建 Buffer 幫你做實際 IO 傳輸 buffer 處理 示範程式 使用 BufferedReader 讀出檔案內容

BufferedReader使用法 Constructor: BufferedReader(Reader in); Reader 是一個 abstract 類別,不能被 new 出來,只能被繼承使用 查API可知道 Reader 被 FileReader 繼承。 而 FileReader 有一 Constructor 為 FileReader(String filename) 因此我們可以 new 一個 FileReader,當作參數傳入BufferedReader 之 Constructor

BufferedWriter使用法 Constructor: BufferedWriter(Writer out); Writer 是一個 abstract 類別,不能被 new 出來,只能被繼承使用 查 API 可知到 Writer 被 FileWriter 繼承。 而 FileWriter 有一 Constructor 為 FileWriter(String filename) 因此我們可以 new 一個 FileWriter,當作參數傳入BufferedWriter 之 Constructor

為何Java如此大費周章 使用BufferedReader為何還要先產生FileReader,再指向檔案名稱? BufferedReader br = new BufferedReader(new FileReader(“Test.txt”)); 因為 BufferedReader 和 BufferedWriter 不只可以做檔案處理之功能 只需置換 BufferedReader 之建構子,即可使用相同的API做出讀取鍵盤輸入和網路傳輸等功能 請注意 BufferedReader 和 BufferedWriter 的建構子為 Reader 和 Writer 之類別

InputStream / OutputStream 在 Java 中,相對應於 Reader / Writer,用來讀取和寫入位元或位元陣列 提供的方法: int read() -- 讀取一個位元 int read(byte[]) – 讀取位元陣列,當資料結尾時,傳回 -1 int read(byte[], int, int) void write(int) – 寫入整數 void write(byte[]) – 寫入 1 個位元組陣列 void write(byte[], int, int)

InputStream / OutputStream 對於位元的檔案 IO,Java 程式是開啟 FileOutputStream 和 FileInputStream 串流,如: FileOutputStream output = new FileOutputStream(file); … FileInputStream input = new FileInputStream(name); 參數可以是檔案路徑字串,或是 File 物件

Example public class Untitled1 { public Untitled1() { } public static void main(String[] args) throws IOException { Untitled1 untitled11 = new Untitled1(); String[] filenames; FileInputStream input = new FileInputStream("c:\\ip.txt"); FileOutputStream output = new FileOutputStream("c:\\clone.jpg"); int b; while ( (b = input.read()) != -1 ) { output.write(b); System.out.println(b); // 顯示出一個 pixel 的數值 output.close(); input.close();

Your Turn 建立一個 Java 程式從命令參數列輸入個數和最大值 maxValue,然後使用亂數產生 0 ~ maxValue 的整數值,以每個整數間隔一個 Tab,每一列 5 個的方式將整數以字元方式寫入文字檔案中。 產生亂數的方式:Math.random() 記得處理例外 試利用 BufferedReader 中的 readLine() 來將剛剛產生的檔案內容讀出 See FileIO.java