Java多執行緒與網路程式設計綜合使用
最近重新看多執行緒與網路程式設計這一塊的知識,好久沒碰這一塊了,都忘得差不多了,這裡將這兩個模組的知識串接一下。同時處理多執行緒與網路程式設計最為經典的例子莫過於聊天室,那我就聊天室案例作為一個回顧。
首先,我們來看以下程式碼:
package MultiTCP;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 必須先啟動再連線
* 1、建立伺服器 指定埠 ServerSocket(int port)
* 2、接收客戶端的連線 阻塞式
* 3、傳送資料+接收資料
*
* 接收多個客戶端
*/
@SuppressWarnings("all")
public class MultiServer {
public static void main(String[] args) throws IOException {
//1、建立伺服器 指定埠
ServerSocket server = new ServerSocket(8888);
while(true)//死迴圈 一個accept 一個客戶端
{
//2、接收客戶端的連線
Socket socket = server.accept();
System.out.println("一個客戶端建立連線" );
//2、傳送資料
String msg = "歡迎使用";
//3、輸出流
/*BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream()));
bw.write(msg);
bw.newLine();//一定要加行結束符,不然讀不到資料
bw.flush();*/
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg);
dos.flush();
}
}
}
package MultiTCP;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 1、建立客戶端 必須指定伺服器+埠 此時就在連線
* Socket(String host,int port)
* 2、接收資料+傳送資料
*/
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//1、建立客戶端 必須指定伺服器+埠 此時就在連線
Socket client = new Socket("localhost",8888);
//2、接收資料
/*BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
String echo = br.readLine();//阻塞式方法
System.out.println(echo);*/
DataInputStream dis = new DataInputStream(client.getInputStream());
String echo = dis.readUTF();
System.out.println(echo);
}
}
以上程式碼存在的問題
伺服器為一個客戶端傳送資料完畢才能連線下一個客戶端。
因此,為了解決上述的問題,我們需要為伺服器端建立多執行緒操作。
首先我們需要為聊天室添加發送資料和接收資料。
package CSNet;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 建立伺服器
*/
@SuppressWarnings("all")
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
Socket client = server.accept();
//寫出資料
//輸入流
DataInputStream dis = new DataInputStream(client.getInputStream());
String msg = dis.readUTF();
System.out.println("伺服器收到"+msg);
//輸出流
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("伺服器傳送給客戶端"+msg);
dos.flush();
}
}
package CSNet;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 建立客戶端:傳送資料+接收資料
* 寫出資料:輸出流
* 讀取資料:輸入流
* 輸入流與輸出流在同一個執行緒內,因此我們應該讓 輸入流與輸出流彼此獨立
*/
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client = new Socket("localhost",9999);
//控制檯的輸入流
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
DataInputStream dis = new DataInputStream(client.getInputStream());
while(true)
{
String info = console.readLine();
//輸出流
dos.writeUTF(info);
dos.flush();
//輸入流
String msg = dis.readUTF();
System.out.println(msg);
}
}
}
以上的程式碼存在輸入流與輸出流在同一個執行緒內問題,因此我們應該讓輸入流與輸出流彼此獨立。
接下來我們是需要實現多執行緒,讓輸入流與輸出流分離。對客戶端實現多執行緒。
客戶端傳送資料
package ThreadNet;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 傳送資料執行緒:用於傳送資料
*/
public class Send implements Runnable{
//控制檯的輸入流
private BufferedReader console;
//管道的資料輸出流
private DataOutputStream dos;
//控制執行緒標識
private boolean isRunning = true;
//初始化
public Send() {
console = new BufferedReader(new InputStreamReader(System.in));
}
public Send(Socket client)
{
this();
try {
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
}
}
//1、從控制檯接收資料
private String getMsgFromConsole()
{
try {
return console.readLine();
} catch (IOException e) {
}
return "";
}
/**
* 1、從控制檯接收資料
* 2、傳送資料
*/
public void send()
{
String msg = getMsgFromConsole();
try {
if(null!=msg&& !msg.equals(""))
{
dos.writeUTF(msg);
dos.flush();//強制重新整理
}
} catch (IOException e) {
isRunning = false;//傳送失敗,提示關閉執行緒
CloseUtil.closeAll(dos,console);//如果不能傳送成功,直接關閉流。
}
}
@Override
public void run() {
//執行緒體
while(isRunning)
{
send();
}
}
}
客戶端接收資料
package ThreadNet;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
/**
* 接收執行緒:用於接收資料
*/
public class Receive implements Runnable{
//管道的資料輸入流
private DataInputStream dis ;
//執行緒標識
private boolean isRunning = true;
public Receive() {
}
public Receive(Socket client) {
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
}
}
//接收資料的方法
public String receive()
{
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
}
return msg;
}
@Override
public void run() {
//執行緒體
while(isRunning){
System.out.println(receive());
}
}
}
客戶端
package ThreadNet;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 建立客戶端:傳送資料+接收資料
* 寫出資料:輸出流
* 讀取資料:輸入流
* 輸入流與輸出流在同一個執行緒內 應該獨立出來
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client = new Socket("localhost",9999);
new Thread(new Send(client)).start();//一條路徑
new Thread(new Receive(client)).start();//一條路徑
}
}
伺服器
package ThreadNet;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 建立伺服器
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
while(true){
Socket client = server.accept();
//寫出資料
//輸入流
DataInputStream dis = new DataInputStream(client.getInputStream());
//輸出流
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
while(true)
{
String msg = dis.readUTF();
//System.out.println(msg);
dos.writeUTF("伺服器收到資料並返回"+msg);
dos.flush();
}
}
}
}
關閉流
package ThreadNet;
import java.io.Closeable;
import java.io.IOException;
/**
* 關閉流的方法
*/
public class CloseUtil {
public static void closeAll(Closeable ... io)
{
for(Closeable temp:io)
{
if(null==temp)
{
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
這個方仍然存在問題,伺服器端只能夠一個一個的接收,必須要等到上一條執行完,才能進入下一條,存在所謂的先後順序,並不具備多執行緒的功能。因此我們也需要對伺服器進行多執行緒。
伺服器
package MultiServer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 建立伺服器
*/
public class Server {
private List<MyChannel> all = new ArrayList<>();
public static void main(String[] args) throws IOException {
new Server().start();
}
public void start() throws IOException
{
ServerSocket server = new ServerSocket(9999);
while(true)
{
Socket client = server.accept();
MyChannel channel = new MyChannel(client);
all.add(channel);//統一管理
new Thread(channel).start();//一條道路
}
}
/**
* 內部類
* 一個客戶端 一條道路
* 1、輸入流
* 2、輸出流
* 3、接收資料
* 4、傳送資料
* @author Administrator
*
*/
class MyChannel implements Runnable
{
private DataInputStream dis;
private DataOutputStream dos;
private boolean isRunning = true;
private String name;
public MyChannel() {
}
//初始化
public MyChannel(Socket client)
{
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
this.name = dis.readUTF();
//System.out.println(this.name);
this.send("歡迎進入聊天室");
sendOthers(this.name+"進入了聊天室",true);
} catch (IOException e) {
CloseUtil.closeAll(dos,dis);
isRunning = false;
}
}
//接收資料
private String receive()
{
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
CloseUtil.closeAll(dis);
isRunning = false;
all.remove(this);//移除自身
}
return msg;
}
//傳送資料
private void send(String msg)
{
if(null==msg||msg.equals(""))
{
return;
}
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
CloseUtil.closeAll(dos);
isRunning = false;
all.remove(this);//移除自身
}
}
//傳送給其他客戶端
private void sendOthers(String msg,boolean sys)
{
//是否為私聊 約定
if(msg.startsWith("@")&& msg.indexOf(":")>-1)
{
//獲取name
String name = msg.substring(1,msg.indexOf(":"));
String contant = msg.substring(msg.indexOf(":")+1);
for(MyChannel other:all)
{
if(other.name.equals(name))
{
other.send(this.name+"對你悄悄的說:"+contant);
}
}
}
else {
for(MyChannel other:all)
{
if(other ==this)
{
continue;
}
if(sys==true)//系統資訊
{
other.send("系統資訊:"+msg);
}
else {
//傳送其它客戶端
other.send(this.name+"對所有人說"+msg);
}
}
}
/*
//遍歷容器
for(MyChannel others:all)
{
if(others == this)
{
continue;
}
//傳送給其他客戶端
others.send(msg);
}*/
}
@Override
public void run() {
while(isRunning)
{
sendOthers(receive(),false);
}
}
}
}
傳送資訊(供客服端使用)
package MultiServer;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 傳送資料執行緒:用於傳送資料
*/
public class Send implements Runnable{
//控制檯輸入流
private BufferedReader console;
//管道輸出流
private DataOutputStream dos;
//控制執行緒標識
private boolean isRunning = true;
//名稱
private String name;
//初始化
public Send() {
console = new BufferedReader(new InputStreamReader(System.in));
}
public Send(Socket client,String name)
{
this();
try {
dos = new DataOutputStream(client.getOutputStream());
this.name = name;
send(this.name);
} catch (IOException e) {
//e.printStackTrace();
}
}
//1、從控制檯接收資料
private String getMsgFromConsole()
{
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
/**
* 1、從控制檯接收資料
* 2、傳送資料
*/
public void send(String msg)
{
try {
if(null!=msg&& !msg.equals(""))
{
dos.writeUTF(msg);
dos.flush();//強制重新整理
}
} catch (IOException e) {
//e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dos,console);
}
}
@Override
public void run() {
while(isRunning)
{
send( getMsgFromConsole());
}
}
}
接收資訊(供客服端使用)
package MultiServer;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
/**
* 接收執行緒:用於接收資料
*/
public class Receive implements Runnable{
//管道的資料輸入流
private DataInputStream dis ;
//執行緒標識
private boolean isRunning = true;
public Receive() {
}
public Receive(Socket client) {
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
}
}
//接收資料的方法
public String receive()
{
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
}
return msg;
}
@Override
public void run() {
//執行緒體
while(isRunning){
System.out.println(receive());
}
}
}
客戶端
package MultiServer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 建立客戶端:傳送資料+接收資料
* 寫出資料:輸出流
* 讀取資料:輸入流
* 輸入流與輸出流在同一個執行緒內 應該獨立出來
* 加入名稱
*/
public class Client {
public static void main(String[] args) throws IOException
{
System.out.println("請輸入使用者名稱:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String name = br.readLine();
if(name.equals(""))
{
return;
}
Socket client = new Socket("localhost",9999);
new Thread(new Send(client,name)).start();//一條路徑
new Thread(new Receive(client)).start();//一條路徑
}
}
關閉流
package MultiServer;
import java.io.Closeable;
import java.io.IOException;
/**
* 關閉流的方法
*/
public class CloseUtil {
public static void closeAll(Closeable ... io)
{
for(Closeable temp:io)
{
if(null==temp)
{
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
執行結果:
Client1
Client2
相關推薦
Java多執行緒與網路程式設計綜合使用
最近重新看多執行緒與網路程式設計這一塊的知識,好久沒碰這一塊了,都忘得差不多了,這裡將這兩個模組的知識串接一下。同時處理多執行緒與網路程式設計最為經典的例子莫過於聊天室,那我就聊天室案例作為一個回顧。 首先,我們來看以下程式碼: package MultiT
java多執行緒與併發程式設計詳解
一、多執行緒1、作業系統有兩個容易混淆的概念,程序和執行緒。程序:一個計算機程式的執行例項,包含了需要執行的指令;有自己的獨立地址空間,包含程式內容和資料;不同程序的地址空間是互相隔離的;程序擁有各種資源和狀態資訊,包括開啟的檔案、子程序和訊號處理。執行緒:表示程式的執行流程
《瘋狂Java講義》讀書筆記(十):多執行緒,網路程式設計,類載入機制與反射
第十六章:多執行緒1、一般而言,程序包含如下3個特徵:獨立性,動態性,併發性。併發性和並行性是兩個概念,並行指同一時刻,有多條指令在多個處理器上同時執行;併發指同一時刻只能有一條指令執行,但多個程序指令
【鐵匠Smith先生的專欄】關注Linux系統軟體開發、多媒體圖形技術、Linux OS技術、多程序多執行緒併發網路程式設計、架構模式研究與實踐、AI等新技術動向、C/C++最新程式設計技術、開原始碼整合與應用等
關注Linux系統軟體開發、多媒體圖形技術、Linux OS技術、多程序多執行緒併發網路程式設計、架構模式研究與實踐、AI等新技術動向、C/C++最新程式設計技術、開原始碼整合與應用等...
Java語言程式設計-進階篇(七)多執行緒與並行程式設計【上】
1.簡單的多執行緒例子package test; public class hello { public static void main(String args[]){ Runnable printA = new PrintChar('a',100);
關於程序,執行緒,多程序和多執行緒的網路程式設計
程序執行緒網路 多工程式設計 : 可以有效的利用計算機資源,同時執行多個任務 程序 : 程序就是程式在計算機中一次執行的過程 程序和程式的區別: 程式是一個靜態檔案的描述,不佔計算機的系統資源 程序是一個動態的過程,佔有cpu記憶體等資源,有一定的生命週期 * 同一個程式的不同執行過程即為不同的程序
總結-Java多執行緒與高併發簡記
1、什麼是多執行緒? 一個程序可以開啟多個執行緒,每個執行緒可以併發/並行執行不同任務。 2、Java多執行緒實現方式 2.1、繼承Thread類 2.2、實現Runnable介面方式實現多執行緒 2.3、使
多執行緒與併發程式設計
前言 多執行緒併發程式設計是Java程式設計中重要的一塊內容,也是面試重點覆蓋區域,所以學好多執行緒併發程式設計對我們來說極其重要,下面跟我一起開啟本次的學習之旅吧。 正文 執行緒與程序 1 執行緒:程序中負責程式執行的執行單元執行緒本身依靠程
Java多執行緒與鎖模型-順序鎖與資源鎖
順序鎖:當應用程式使用2把以上的鎖時,就容易出現因為多執行緒獲取鎖的順序不同而死鎖的情形,包括交叉獲取應用程式範圍內的多把已知鎖、交叉獲取應用程式與第三方方法中的多把鎖而造成的順序死鎖。絕大多數死鎖都是因為CPU排程多執行緒時,在執行時序上是交叉進行的而造成亂序獲得多把鎖,從
javaSE (四十)網路程式設計(TCP傳輸、伺服器多執行緒、網路程式設計練習:反轉字串、上傳檔案)
1、TCP傳輸: 1.客戶端 建立Socket連結服務端(指定ip地址,埠號),通過ip地址找到對應的伺服器 呼叫Socket的getInputStream和getOutputStream方法獲取和伺服器端相連的IO流 2.伺服器端 建立Se
Java多執行緒下載網路檔案
新建一個JavaGUI介面 package Download; import java.awt.EventQueue; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.Action
更多免費初級中級高階大資料java視訊教程下載 加(微***信((號keepper,請備註java或掃下面2二3維4碼Java多執行緒與併發庫高階應用視訊教程下載
更多免費初級中級高階大資料java視訊教程下載 加(微***信((號keepper,請備註java或掃下面2二3維4碼Java多執行緒與併發庫高階應用視訊教程下載java視訊教程01_傳智播客_張孝祥_傳統執行緒技術回顧.rarjava視訊教程02_傳智播客_張孝祥_傳統定時器技術回顧.rarjava視訊教程
Java多執行緒與併發(三)
Condition等待和喚醒 在我們的並行程式中,避免不了某些寫成要預先規定好的順序執行,例如:先新增後修改,先買後賣,先進後出,對於這些場景,使用JUC的Conditon物件再合適不過了。 JUC中提供了Condition物件,用於讓指定執行緒等待與喚
Java多執行緒與併發(二)
Synchronized執行緒同步機制 很多執行緒同時對同一個資料或者檔案進行訪問的時候,對於這個檔案如果進行併發讀寫可能會產生問題。 多執行緒機制來保證同一個時間,只有一個執行緒對這個資源進行讀寫,來保證多執行緒環境下是健壯的。 程式碼案例:
Java多執行緒與併發(一)
多執行緒與併發的基礎問題 併發就是指程式同時處理多個任務的能力(一個程式被多個使用者訪問都能看到自己預期的結果) 併發的根源在於對多工情況下訪問資源的有效控制! 併發背後的問題 public class DownloadSimple {
Java多執行緒與android多執行緒
https://www.cnblogs.com/zoe-mine/p/7954605.html java多執行緒以及Android多執行緒執行緒和程序的區別執行緒和程序的本質:由CPU進行排程的併發式執行任務,多個任務被快速輪換執行,使得巨集觀上具有多個執行緒或者程
windows多執行緒和網路程式設計
第 10 章 多執行緒與網路程式設計初步 教學提示:Windows 是一個支援多工的作業系統。當在一個程式中需要啟動另外一 個程式時,需要用到多程序的程式設計方式。如果一個程序中有一些相似的任務需要同時推進, 可以為每個任務建立一個執行緒,從而形成多執行緒的程式設計。隨著網路技術的廣泛應用,網路 程式設計
Java多執行緒與併發庫高階應用之倒計時計數器CountDownLatch
CountDownLatch類是一個倒計時計數器,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。用給定的計數初始化 CountDownLatch。由於呼叫了countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之後,
java多執行緒與高併發庫應用(二)執行緒建立和定時任務Timer
1、建立執行緒的兩種方式, 通過start, 執行run方法。 第一種實現runnable, 定義類實現Runnable介面 重寫Runnable介面中的run方法 通過Thread建立執行緒物件 將Runnable介面的子類物件作為實際引數傳遞
JAVA多執行緒與佇列
JAVA 已經給我們提供了比較好的佇列實現Queue,繼承於Collection。 本次我使用的是BlockingQueue,繼承於Queue。 在Concurrent包中,BlockingQueue很好的解決了多執行緒中,如何高效安全“傳輸”資料的問題。通