用java多线程实现服务器与客户端原理

用java多线程实现服务器与客户端原理,第1张

服务器端:
import javaawt;
import javaawtevent;
import javaxswing;
import javaio;
import javanet;
import javautilVector;
public class OneToMoreServer extends JFrame implements ActionListener{
JPanel contentPane;
JLabel jLabel2 = new JLabel();
JTextField jTextField2 = new JTextField("4700");
JButton jButton1 = new JButton();
JLabel jLabel3 = new JLabel();
JTextField jTextField3 = new JTextField();
JButton jButton2 = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea jTextArea1 = new JTextArea();
ServerSocket server = null;
Socket socket = null;BufferedReader instr =null;PrintWriter os=null ;
Vector vector=new Vector();
boolean serverRun=true;
boolean clientRun=true;
//Construct the frame
public OneToMoreServer() {
jbInit();

}

class MyThread extends Thread{//该线程负责接收数据
Socket socketI=null;
BufferedReader br=null;
public MyThread(Socket socket)
{
socketI=socket;
}
public void run(){
try{
while(clientRun){
thissleep(100);
br= new BufferedReader(new InputStreamReader(socketIgetInputStream()));
if(brready()){ //检查是否有数据
jTextArea1append("接收到来自客户端("+socketIgetInetAddress()toString()+")的消息: "+brreadLine()+"\n");
}
}
}catch(Exception ex){JOptionPaneshowMessageDialog(null,extoString());}
}
}

public void actionPerformed(ActionEvent e){
if(egetSource()==jButton1){
int port=IntegerparseInt(jTextField2getText()trim());
//监听指定端口
try
{
server = new ServerSocket(port);
new Thread(new ListenClient())start();
}
catch(IOException ex)
{
JOptionPaneshowMessageDialog(null,extoString());
}
}
if(egetSource()==jButton2){
String msg=jTextField3getText()trim();
if(msglength()!=0)
sendData("hello");
}
}
//该线程负责监听指定端口
class ListenClient implements Runnable
{
public void run()
{
try{
if(jButton1getText()trim()equals("侦听")){
jButton1setText("正在侦听");
while(serverRun)
{
Socket socketI=serveraccept();//有客户端连入时建立一个线程监听客户端发送的消息
vectoradd(socketI);
jButton1setText("正在聊天");
jTextArea1append("客户端"+socketIgetInetAddress()toString()+"已经连接到服务器\n");
MyThread t=new MyThread(socketI);
tstart();
}
}
}catch(Exception ex){
JOptionPaneshowMessageDialog(null,extoString());
}
}
}
private void sendData(String s){//发送数据
try{
for(int i=0;i<vectorsize();i++)
{
//怎么广播
//向每个客户端发送一条消息
Socket socket=(Socket)vectorget(i);
os= new PrintWriter(socketgetOutputStream());
osprintln(s);
osflush();
}
}catch(Exception ex){
}
}
private void jbInit() {
contentPane = (JPanel) thisgetContentPane();
contentPanesetLayout(null);
thissetSize(new Dimension(540, 340));
thissetTitle("服务器");
jLabel2setBounds(new Rectangle(22, 27, 72, 28));
jLabel2setText("端口号");
jLabel2setFont(new javaawtFont("宋体", 0, 14));
jTextField2setBounds(new Rectangle(113, 27, 315, 24));

jButton1setBounds(new Rectangle(440, 28, 73, 25));
jButton1setFont(new javaawtFont("Dialog", 0, 14));
jButton1setBorder(BorderFactorycreateEtchedBorder());
jButton1setActionCommand("jButton1");
jButton1setText("侦听");
jLabel3setBounds(new Rectangle(23, 57, 87, 28));
jLabel3setText("请输入信息");
jLabel3setFont(new javaawtFont("宋体", 0, 14));
jTextField3setBounds(new Rectangle(114, 60, 314, 24));
jTextField3setText("");
jButton2setText("广播");
jButton2setActionCommand("jButton1");
jButton2setBorder(BorderFactorycreateEtchedBorder());
jButton2setFont(new javaawtFont("Dialog", 0, 14));
jButton2setBounds(new Rectangle(440, 58, 73, 25));
jScrollPane1setBounds(new Rectangle(23, 92, 493, 189));

contentPaneadd(jTextField2, null);
contentPaneadd(jButton1, null);
contentPaneadd(jLabel3, null);
contentPaneadd(jTextField3, null);
contentPaneadd(jButton2, null);
contentPaneadd(jScrollPane1, null);
contentPaneadd(jLabel2, null);
jScrollPane1getViewport()add(jTextArea1, null);
jButton1addActionListener(this);
jButton2addActionListener(this);
thisaddWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
try{
socketclose();
instrclose();
Systemexit(0);
}catch(Exception ex){
//JOptionPaneshowMessageDialog(null,extoString());
}

}
});
}
public static void main(String arg[]){
JFramesetDefaultLookAndFeelDecorated(true);
OneToMoreServer frm=new OneToMoreServer();
frmsetDefaultCloseOperation(JFrameEXIT_ON_CLOSE);
frmsetVisible(true);
}
}
客户端
import javaawt;
import javaawtevent;
import javaxswing;
import javaio;
import javanet;
public class Client extends JFrame implements ActionListener{
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField jTextField1 = new JTextField("127001");
JLabel jLabel2 = new JLabel();
JTextField jTextField2 = new JTextField("4700");
JButton jButton1 = new JButton();
JLabel jLabel3 = new JLabel();
JTextField jTextField3 = new JTextField();
JButton jButton2 = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea jTextArea1 = new JTextArea();
BufferedReader instr =null;
Socket socket = null;
PrintWriter os=null;
public Client() {
jbInit();
}
class MyThread extends Thread{
public void run(){
try{
os=new PrintWriter(socketgetOutputStream());
instr=new BufferedReader(new InputStreamReader(socketgetInputStream()));
while(true)
{
thissleep(100);
if(instrready())
{
jTextArea1append("接收到来自服务器的消息: "+instrreadLine()+"\n");
}
}
}catch(Exception ex){
JOptionPaneshowMessageDialog(null,extoString());
}
}
}
public void actionPerformed(ActionEvent e){
if(egetSource()==jButton1){
String ip=jTextField3getText()trim();
int port=IntegerparseInt(jTextField2getText()trim());
connectServer(ip,port);
}
if(egetSource()==jButton2){
String s=thisjTextField3getText()trim();
sendData(s);
}
}
private void connectServer(String ip,int port){//连接
try{
if(jButton1getText()trim()equals("连接")){
jButton1setText("连接服务器");
socket=new Socket(ip,port);
jButton1setText("正在聊天");
MyThread t=new MyThread();
tstart();
}
}catch(Exception ex){
JOptionPaneshowMessageDialog(this,extoString());
}
}
private void sendData(String s){//发送数据
try{
os = new PrintWriter(socketgetOutputStream());
osprintln(s);
osflush();
thisjTextArea1append("向服务器发送消息:"+s+"\n");
}catch(Exception ex){
JOptionPaneshowMessageDialog(this,extoString());
}
}
private void jbInit() {
contentPane = (JPanel) thisgetContentPane();
jLabel1setFont(new javaawtFont("宋体", 0, 14));
jLabel1setText("服务器名称");
jLabel1setBounds(new Rectangle(20, 22, 87, 28));
contentPanesetLayout(null);
thissetSize(new Dimension(540, 340));
thissetTitle("客户端");

jTextField1setBounds(new Rectangle(114, 26, 108, 24));
jLabel2setBounds(new Rectangle(250, 25, 72, 28));
jLabel2setText("端口号");
jLabel2setFont(new javaawtFont("宋体", 0, 14));
jTextField2setBounds(new Rectangle(320, 27, 108, 24));

jButton1setBounds(new Rectangle(440, 28, 73, 25));
jButton1setFont(new javaawtFont("Dialog", 0, 14));
jButton1setBorder(BorderFactorycreateEtchedBorder());
jButton1setActionCommand("jButton1");
jButton1setText("连接");
jLabel3setBounds(new Rectangle(23, 57, 87, 28));
jLabel3setText("请输入信息");
jLabel3setFont(new javaawtFont("宋体", 0, 14));
jTextField3setBounds(new Rectangle(114, 60, 314, 24));

jButton2setText("发送");
jButton2setActionCommand("jButton1");
jButton2setBorder(BorderFactorycreateEtchedBorder());
jButton2setFont(new javaawtFont("Dialog", 0, 14));
jButton2setBounds(new Rectangle(440, 58, 73, 25));
jScrollPane1setBounds(new Rectangle(23, 92, 493, 189));

contentPaneadd(jLabel1, null);
contentPaneadd(jTextField1, null);
contentPaneadd(jLabel2, null);
contentPaneadd(jTextField2, null);
contentPaneadd(jButton1, null);
contentPaneadd(jLabel3, null);
contentPaneadd(jTextField3, null);
contentPaneadd(jButton2, null);
contentPaneadd(jScrollPane1, null);
jScrollPane1getViewport()add(jTextArea1, null);
jButton1addActionListener(this);
jButton2addActionListener(this);
thisaddWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
try{
socketclose();instrclose();osclose();Systemexit(0);
}catch(Exception ex){
JOptionPaneshowMessageDialog(null,extoString());
}
}
});
}
public static void main(String arg[]){
JFramesetDefaultLookAndFeelDecorated(true);
Client frm=new Client();
frmsetVisible(true);
}
}

itjobJava老师讲过:1)线程堆栈概述及基础知识

2)线程堆栈的生成原理以及相关工具

3)不同JVM线程堆栈的格式的差异(SunHotSpot、IBMJRE、OracalJRockit)

4)线程堆栈日志介绍以及解析方法

5)线程堆栈的分析和相关的技术

6)常见的问题模板(线程竟态、死锁、IO调用挂死、垃圾回收/问题、死循环等)

7)线程堆栈问题实例分析

我希望这一系列的培训能给你带来确实的帮助,所以请持续关注每周的文章更新。

但是如果我在学习过程中有疑问或者无法理解文章中的内容该怎么办?

不用担心,把我当做你的导师就好。任何关于线程堆栈的问题都可以咨询我(前提是问题不能太low)。请随意选择下面的几种方式与我取得联系:

1)直接本文下面发表评论(不好意思的话可以匿名)

2)将你的线程堆栈数据提交到RootCauseAnalysisforum

3)发Email给我,地址是@@hotmail

能帮我分析我们产品上遇到的问题么?

当然可以,如果你愿意的话可以把你的堆栈现场数据通过邮件或论坛RootCauseAnalysisforum发给我。处理实际问题是才是学习提升技能的王道。

我真心期望大家能够喜欢这个培训。所以我会尽我所能去为你提供高质量的材料,并回答大家的各种问题。

在介绍线程堆栈分析技术和问题模式之前,先要给大家讲讲基础的内容。所以在这篇帖子里,我将先覆盖到最基本的内容,这样大家就能更好的去理解JVM、中间件、以及JavaEE容器之间的交互。

JavaVM概述

Java虚拟机是JaveEE平台的基础。它是中间件和应用程序被部署和运行的地方。

JVM向中间件软件和你的Java/JavaEE程序提供了下面这些东西:

_(二进制形式的)Java/JavaEE程序运行环境

_一些程序功能特性和工具(IO基础设施,数据结构,线程管理,安全,监控等等)

_借助垃圾回收的动态内存分配与管理

你的JVM可以驻留在许多的 *** 作系统(Solaris,AIX,Windows等等)之上,并且能根据你的物理服务器配置,你可以在每台物理/虚拟服务器上安装1到多个JVM进程

JVM与中间件之间的交互

下面这张图展示了JVM、中间件和应用程序之间的高层交互模型。

如你所见,标准JavaEE应用程序的线程的分配实在中间件内核与JVM之间完成的。(当然也有例外,应用程序可以直接调用API来创建线程,这种做法并不常见,而且在使用的过程中也要特别的小心)

同时,请注意一些线程是由JVM内部来进行管理的,典型的例子就是垃圾回收线程,JVM内部使用这个线程来做并行的垃圾回收处理。

因为大多数的线程分配都是由JavaEE容器完成的,所以能够理解和认识线程堆栈跟踪,并能从线程堆栈数据中识别出它来,对你而言很重要这可以让你能够快速的知道JavaEE容器正要执行的是什么类型的请求

从一个线程转储堆栈的分析角度来看,你将能了解从JVM发现的线程池之间的不同,并识别出请求的类型

最后一节会向你提供对于HotSopVM而言什么是JVM线程堆栈的一个概述,还有你将会遇到的各种不同的线程而对IBMVM线程堆栈形式详细内容将会在第四节向你提供

请注意你可以从根本原因分析论坛获得针对本文的线程堆栈示例

JVM线程堆栈——它是什么

JVM线程堆栈是一个给定时间的快照,它能向你提供所有被创建出来的Java线程的完整清单

一、 *** 作系统中线程和进程的概念
现在的 *** 作系统是多任务 *** 作系统。多线程是实现多任务的一种方式。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如javaexe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
“同时”执行是人的感觉,在线程之间实际上轮换执行。
二、Java中的线程
在Java中,“线程”指两件不同的事情:
1、javalangThread类的一个实例;
2、线程的执行。
使用javalangThread类或者javalangRunnable接口编写代码来定义、实例化和启动新线程。
一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。
Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。
一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。
一旦创建一个新的线程,就产生一个新的调用栈。
线程总体分两类:用户线程和守候线程。
当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由 *** 作系统或者用户自己创建的

首先确认你是cpu密集型的还是io密集型的,

如果是cpu密集型的线程数可以设置到和cpu个数一致,

如果是io密集型的,首先需要确认你io wait的时间,线程数和io wait时间成正比, 具体需要根据测试得出。

1) 线程堆栈概述及基础知识 2) 线程堆栈的生成原理以及相关工具 3) 不同JVM线程堆栈的格式的差异(Sun HotSpot、IBM JRE、Oracal JRockit) 4) 线程堆栈日志介绍以及解析方法 5) 线程堆栈的分析和相关的技术 6) 常见的问题模板(线程竟态、死锁

一:newCachedThreadPool
(1)缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse,如果没有,就建立一个新的线程加入池中;
(2)缓存型池子,通常用于执行一些生存周期很短的异步型任务;因此一些面向连接的daemon型server中用得不多;
(3)能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。
(4)注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止
二:newFixedThreadPool
(1)newFixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程
(2)其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子
(3)和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器
(4)从方法的源代码看,cache池和fixed 池调用的是同一个底层池,只不过参数不同:
fixed池线程数固定,并且是0秒IDLE(无IDLE)
cache池线程数支持0-IntegerMAX_VALUE(显然完全没考虑主机的资源承受能力),60秒IDLE
三:ScheduledThreadPool
(1)调度型线程池
(2)这个池子里的线程可以按schedule依次delay执行,或周期执行
四:SingleThreadExecutor
(1)单例线程,任意时间池中只能有一个线程
(2)用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/12768554.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-27
下一篇 2023-05-27

发表评论

登录后才能评论

评论列表(0条)

保存