多線程 網絡編程 文件上傳案例多線程


Day13 多線程

3).多線程的好處:

提高程序的運行效率,提高用戶的體驗度。 線程不會因為等待某個資源而進入等待狀態

 

 

 

 

創建新的線程:

 *    定義類繼承Thread

 *    重寫方法run

 *    創建Thread子類的對象

 *    調用子類對象的方法 start()

 *    

 *  為什么繼承Thread

 *    Thread類是線程對象類

 *    繼承了Thread,子類也是線程對象

 *  

 *  為什么重寫run

 *    Sun工程師,不清楚其他人員用線程做什么

 *    全部寫在run

 *  

 *  為什么調用start

 *    線程: JVM利用Windows中的功能實現

 *    start() 調用 本地方法,開啟的線程

 

 

 2.Thread類的方法,可以獲取到線程名字

 *    String getName()

 *    

 *  Thread類方法 setName(String name)

 *  設置線程名字

 *  

 *  獲取主線程名

 *    Thread,定義靜態方法

 *    static Thread currentThread() 返回當前線程

 *    什么是當前線程: 現在運行的線程

 

 

第二種方式實現Runnable接口避免了單繼承的局限性,所以較為常用。實現Runnable接口的方式,更加的符合面向對象,線程分為兩部分,一部分線程對象,一部分線程任務。

第一種方式繼承Thread類,線程對象和線程任務耦合在一起。一旦創建Thread類的子類對象,既是線程對象,有又有線程任務。

實現runnable接口,將線程任務單獨分離出來封裝成對象,類型就是Runnable接口類型。Runnable接口對線程對象和線程任務進行解耦。

 

3.創建線程程序第二個方式,接口方式

 *  java.lang.Runnable

 *    定義類實現接口Runnable

 *    重寫抽象方法run

 *    創建Thread類對象,Thread(Runnable r)

 *    調用Thread對象start()方法

 

4. 售票代碼,單獨定義方法

 *  pay方法,所有的代碼,全是線程操作的共享數據

 *  同步整個方法,方法的定義修飾符,加同步

 *  

 *  同步方法有鎖嗎,同步方法的鎖就是this對象

 *  

 *  靜態同步方法有鎖嗎

 *    靜態方法的對象鎖可不是this

 *    鎖是 本類.class對象

 *    Ticket.class

 

 

當一個線程在執行操作共享數據的多條代碼過程中,其他線程參與了運算。就會導致線程安全問題的產生。

 

 

6.其實,多線程程序並不能提高程序的運行速度,但能夠提高程序運行效率,CPU的使用率更高。

 

 

7.思考:線程對象調用 run方法和調用start方法區別?

線程對象調用run方法不開啟線程,僅是對象調用方法。線程對象調用start開啟線程,並讓jvm調用run方法在開啟的線程中執行。

 

2:請描述在什么樣的情況下會出現線程安全的問題。

線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態

變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程

同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。

 

6.java中提供了線程同步機制,它能夠解決上述的線程安全問題,請分別寫出他們的格式

3.1同步代碼塊: 在代碼塊聲明上 加上synchronized

synchronized (鎖對象) {

可能會產生線程安全問題的代碼

}

3.2同步方法:在方法聲明上加上synchronized

public synchronized void method(){

       可能會產生線程安全問題的代碼

}

 

3.請描述線程的幾個狀態。

線程包含以下幾個狀態:

1. 新建狀態:

   調用構造方法創建線程對象后,線程就會處於新建狀態。  

2.就緒狀態:

   一個新創建的線程並不自動開始運行,要執行線程,必須調用線程的start()

   方法。在調用start()方法后,運行run()方法之前,線程就會處於就緒狀態。

3.運行狀態:

  當線程獲得CPU的資源后,才會進入運行狀態,調用run方法。

4.阻塞狀態:

  當正在運行的線程還沒有運行結束,暫時讓出CPU資源,讓其它處於就緒

  狀態的線程獲得CPU資源。

5.死亡狀態:

  當線程的run方法運行結束后,線程就結束了,此時線程就會死亡狀態。

 

  1. 7.多線程並發和多線程並行是什么呢?

答:兩個或者多個任務發送請求時,CPU只能執行一個,就會安排這些任務交替執行,由於CPU做着高速的切換,間隔的時間比較短,我們看起來像同時執行的,這就是多線程並發。

並行是兩個或多個任務同時執行,前提是多核CPU

  1. 8.同步代碼塊和同步方法的鎖是誰?

;同步代碼塊的鎖可以是任意類型的對象;非靜態同步方法的鎖是this;靜態方法的鎖是該類的字節碼文件。

  1. 3.sleep和wait的區別?

答:(1sleep是讓線程睡眠,必須給相應的睡眠時間,不需要喚醒,時間到了會自動醒來,休眠時不放棄Cpu的執行權。(悲觀鎖機制)

2wait的是讓線程等待,可以傳參也可以不傳參,傳參是在指定的時間后等待,需要被喚醒。等待的時候放棄cpu的執行權。(樂觀鎖機制)

  1. 什么情況下需要同步?

:當多線程並發, 有多段代碼同時執行時, 我們希望某一段代碼執行的過程中CPU不要切換到其他線程工作. 這時就需要同步.

如果兩段代碼是同步的, 那么同一時間只能執行一段, 在一段代碼沒執行結束之前, 不會執行另外一段代碼.

 

  1. 開啟線程:開一個新的方法棧區
  2. 運行是方法run(
  3. 只要開啟一個線程:
  4. 出現一個新的方法棧,運行

當調用一個線程對象start()方法后,此線程對象中的run()方法會被立即執行.(錯誤的)

Start()方法之后進入到”就緒狀態”,等待操作系統分配cpu時間(正確的)

當一個線程對象的sleep()時間到了,會立即恢復運行(錯誤的)

sleep()醒來后,會進入到”就緒狀態”,等待操作系統分配cpu時間(正確的)

Day14 網絡編程

 

InetAdderss類,該類用於封裝一個IP地址,並提供了一系列與IP地址相關的方法,下表中列出了InetAddress類的一些常用方法。

 

 

 TCP協議分哪幾個層

鏈路層:鏈路層用於定義物理傳輸通道通常是對某些網絡連接設備的驅動協議,例如針對光纖、網線提供的驅動。

網絡層:網絡層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。

運輸層:主要使網絡程序進行通信,在進行網絡通信時,可以采用TCP協議,也可以采用UDP協議。

應用層:主要負責應用程序的協議,例如HTTP協議FTP協議等。

C/S 軟件和服務器容易出現更新問題 , 一個更新全部需要更新,

 

B/S 網頁和服務器 維護方便,客戶端一個瀏覽器可以打開多個功能 弊端 所有瀏覽器內容存到瀏覽器  

ip地址  它是由4個字節大小的二進制數來表示

 

 HTTPFTPUDPTCP

 我們涉及到的:

 1.UDP協議:

1.數據要打包發送;

2.數據大小有限制:64K

3.不論是否有接收端,都可以發送。也稱為:無狀態的,不安全的協議。

  應用:視頻廣播,共享屏幕

 2.TCP協議:

1.數據不需要打包,使用""的方式發送和接收;

2.數據大小無限制;

3.發送時,必須要有接收端;

 

1.InetAddress類表示一個IP地址;

2.InetAddress類沒有構造方法,通過靜態方法獲取InetAddress對象;

3.常用方法:

靜態方法:public static InetAddress getByName(String 計算機名/IP地址) :

普通方法:public String getHostAddress():獲取本機IP

 

2.區別在於,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據

TCP通信是嚴格區分客戶端與服務器端的,在通信時,必須先由客戶端去連接服務器端才能實現通信,服務器端不可以主動連接客戶端,並且服務器端程序需要事先啟動,等待客戶端的連接。

JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端

通信時,首先創建代表服務器端的ServerSocket對象,該對象相當於開啟一個服務,並等待客戶端的連接,然后創建代表客戶端的Socket對象向服務器端發出連接請求,服務器端響應請求,兩者建立連接開始通信。

 

 

 

public class TCPServer {

public static void main(String[] args) throws IOException {

//1,創建服務器,等待客戶端連接

ServerSocket serverSocket = new ServerSocket(8888);

Socket clientSocket = serverSocket.accept();

//顯示哪個客戶端Socket連接上了服務器

InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址對象

String ip = ipObject.getHostAddress(); //得到IP地址字符串

System.out.println("小樣,抓到你了,連接我!!" + "IP:" + ip);

 

//7,獲取Socket的輸入流

InputStream in = clientSocket.getInputStream();

//8,創建目的地的字節輸出流   D:\\upload\\192.168.74.58(1).jpg

BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg"));

//9,Socket輸入流中的數據,寫入目的地的字節輸出流中

byte[] buffer = new byte[1024];

int len = -1;

while((len = in.read(buffer)) != -1){

//寫入目的地的字節輸出流中

fileOut.write(buffer, 0, len);

}

 

//-----------------反饋信息---------------------

//10,獲取Socket的輸出流, 作用:寫反饋信息給客戶端

OutputStream out = clientSocket.getOutputStream();

//11,寫反饋信息給客戶端

out.write("圖片上傳成功".getBytes());

 

out.close();

fileOut.close();

in.close();

clientSocket.close();

//serverSocket.close();

}

}

 

public class TCPClient {

public static void main(String[] args) throws IOException {

//2,創建客戶端Socket,連接服務器

Socket socket = new Socket("192.168.74.58", 8888);

//3,獲取Socket流中的輸出流,功能:用來把數據寫到服務器

OutputStream out = socket.getOutputStream();

//4,創建字節輸入流,功能:用來讀取數據源(圖片)的字節

BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg"));

//5,把圖片數據寫到Socket的輸出流中(把數據傳給服務器)

byte[] buffer = new byte[1024];

int len = -1;

while ((len = fileIn.read(buffer)) != -1){

//把數據寫到Socket的輸出流中

out.write(buffer, 0, len);

}

//6,客戶端發送數據完畢,結束Socket輸出流的寫入操作,告知服務器端  (socket流不能判斷讀到-1 結束讀操作 )

socket.shutdownOutput();

 

//-----------------反饋信息---------------------

//12,獲取Socket的輸入流  作用: 讀反饋信息

InputStream in = socket.getInputStream();

//13,讀反饋信息

byte[] info = new byte[1024];

//把反饋信息存儲到info數組中,並記錄字節個數

int length = in.read(info);

//顯示反饋結果

System.out.println( new String(info, 0, length) );

 

//關閉流

in.close();

fileIn.close();

out.close();

socket.close();

}

1.1 文件上傳案例多線程版本

 

 

 

 

實現服務器端可以同時接收多個客戶端上傳的文件。

l 我們要修改服務器端代碼

/*

 * 文件上傳多線程版本, 服務器端

 */

public class TCPServer {

public static void main(String[] args) throws IOException {

//1,創建服務器,等待客戶端連接

ServerSocket serverSocket = new ServerSocket(6666);

 

//實現多個客戶端連接服務器的操作

while(true){

final Socket clientSocket = serverSocket.accept();

//啟動線程,完成與當前客戶端的數據交互過程

new Thread(){

public void run() {

try{

//顯示哪個客戶端Socket連接上了服務器

InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址對象

String ip = ipObject.getHostAddress(); //得到IP地址字符串

System.out.println("小樣,抓到你了,連接我!!" + "IP:" + ip);

 

//7,獲取Socket的輸入流

InputStream in = clientSocket.getInputStream();

//8,創建目的地的字節輸出流   D:\\upload\\192.168.74.58(1).jpg

BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\"+ip+"("+System.currentTimeMillis()+").jpg"));

//9,Socket輸入流中的數據,寫入目的地的字節輸出流中

byte[] buffer = new byte[1024];

int len = -1;

while((len = in.read(buffer)) != -1){

//寫入目的地的字節輸出流中

fileOut.write(buffer, 0, len);

}

 

//-----------------反饋信息---------------------

//10,獲取Socket的輸出流, 作用:寫反饋信息給客戶端

OutputStream out = clientSocket.getOutputStream();

//11,寫反饋信息給客戶端

out.write("圖片上傳成功".getBytes());

 

客戶端發送數據完畢,結束Socket輸出流的寫入操作,告知服務器端

out.close();

fileOut.close();

in.close();

clientSocket.close();

} catch(IOException e){

e.printStackTrace();

}

};

}.start();

}

 

//serverSocket.close();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM