等待唤醒机制,UDP通信和TCP通信
等待唤醒机制
通过等待唤醒机制使各个线程能有效的利用资源。
等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
所谓唤醒的意思就是让 线程池中的线程具备执行资格。
必须注意的是:这些方法都是在 同步中才有效;
同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪 个锁上的线程。而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。
例子:
代码如下:
模拟资源类:
package com.oracle.Resourse; public class Resourse {
public String name;
public String sex;
public boolean flag = false; }
输入线程任务类:
package com.oracle.Resourse; public class InputR implements Runnable{
private int i=0;
private Resourse r=new Resourse(); public InputR(Resourse r){
this.r=r;
}
public void run() {
while(true){
synchronized (r){
if(r.flag){ try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(i%2==0){
r.name="张三";
r.sex="男";
}else{
r.name="LISI";
r.sex="NV";
}
r.flag=true;
r.notify();
}
i++;
}
} }
输出线程任务类:
package com.oracle.Resourse; public class OutputR implements Runnable{ private Resourse r=new Resourse();
public OutputR(Resourse r){
this.r=r; }
public void run() {
while(true){
synchronized (r){
if(r.flag==false){
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(r.name+"..."+r.sex);
r.flag=false;
r.notify(); }
} } }
测试类:
package com.oracle.Resourse; public class TEST { public static void main(String[] args) {
Resourse r=new Resourse();
InputR in=new InputR(r);
OutputR out=new OutputR(r) ;
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start(); } }
结果如下:
InetAddress类
InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法
例子:
public class Example01 {
public static void main(String[] args) throws Exception {
InetAddress local = InetAddress.getLocalHost();
InetAddress remote = InetAddress.getByName("www.oracle.cn");
System.out.println("本机的IP地址:" + local.getHostAddress());
System.out.println("oracle的IP地址:" + remote.getHostAddress());
System.out.println("oracle的主机名为:" + remote.getHostName());
}
}
UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。
DatagramPacket类
该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。
构造方法
发送端一定要明确指出数据的目的地(ip地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数据即可。
DatagramPacket类中的常用方法
DatagramSocket类
DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包
构造方法:
该构造方法用于创建发送端的DatagramSocket对象,在创建DatagramSocket对象时,并没有指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。
该构造方法既可用于创建接收端的DatagramSocket对象,又可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。
常用方法:
例子:
UDP完成数据的发送:
package com.oracle.UdpTcp; import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner; public class UDPSend {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in );
//InetAddress类调用getbyName方法返回一个本类对象
InetAddress i=InetAddress.getByName("192.168.1.171");
//创建DatagramSocket对象,
DatagramSocket ds = new DatagramSocket();
while(true){ //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 //定义字节数组来接收发送端的内容
String mes=sc.next();
byte[] bytes=mes.getBytes();
//装包
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, i, 6666);
ds.send(dp);
} } }
UDP完成数据的接收:
package com.oracle.UdpTcp; import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket; public class UdpS {
public static void main(String[] args) throws IOException {
//1,创建DatagramSocket对象,并指定端口号
DatagramSocket ds = new DatagramSocket(8888);
//创建接收数据的字节数组
byte[] bytes =new byte[1024];
//创建接收数据包
while(true){
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//接收
ds.receive(dp);
//获取数据
String ip=dp.getAddress().getHostAddress();//获取IP地址
int port=dp.getPort();//获取端口号
int length = dp.getLength();//获取多少条数据
System.out.println(ip+"..."+port+"发送的内容为"+new String(bytes,0,length));
} // ds.close();
}
}
TCP通信
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。
ServerSocket类
构造方法
使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。
ServerSocket的常用方法:
ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。
Socket类
构造方法
常用方法;
方法声明 |
功能描述 |
int getPort() |
该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号 |
InetAddress getLocalAddress() |
该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回 |
void close() |
该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源 |
InputStream getInputStream() |
该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据 |
OutputStream getOutputStream() |
该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据 |
例子:
客户端程序:
package com.oracle.Tcp; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket; public class TCPK {
public static void main(String[] args) throws IOException {
//创建socket对象,连接服务器
Socket s=new Socket ("127.0.0.1",7777 );
//通过客户端套接字对象Socket对象中的获取字节输出流的方法
OutputStream out=s.getOutputStream();
//将数据写向服务器
out.write("服务器你好".getBytes());
//接收服务器端的回复
InputStream in=s.getInputStream();
byte[] bytes=new byte[1024];
int len=in.read(bytes);
System.out.println(new String(bytes,0,len));
s.close(); } }
服务器端程序:
package com.oracle.Tcp; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; public class TCPS { public static void main(String[] args) throws IOException {
//创建服务器套接字
ServerSocket ss=new ServerSocket(7777);
//调用ACCEPT方法与客户端创建链接
Socket s=ss.accept();
InputStream in=s.getInputStream();
byte[] bytes=new byte[1024];
int len=in.read(bytes);
System.out.println(new String(bytes,0,len));
//服务器端给回复
OutputStream out=s.getOutputStream();
out.write("收到".getBytes()); } }
文件上传案例
首先编写服务器端程序,用来接收图片。
package com.oracle.TCPS; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random; public class TCPS { public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(7500);//明确端口号
Socket socket=server.accept();
//读取文件,明确数据源
InputStream in=socket.getInputStream();
//明确目的地
File file=new File("e:\\JPG");
//判断文件是否存在
if(!file.exists()){
file.mkdirs();//没有则创建文件夹
}
//域名+毫秒值+6位随机数
// 随机数
String num="";
for(int i=0;i<6;i++){
num+=new Random().nextInt(10);
}
String filename="oracle"+System.currentTimeMillis()+num+".jpg";
FileOutputStream fos=new FileOutputStream(file+File.separator+filename);
//复制‘
int len=0;
byte[] bytes=new byte[1024];
while((len=in.read(bytes))!=-1){
fos.write(bytes,0,len);//往服务器端写
}
//回复客户端
OutputStream out=socket.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
server.close(); } }
客户端程序:
package com.oracle.TCPS; import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException; public class TCPK { public static void main(String[] args) throws UnknownHostException, IOException {
//创建socket对象,连接服务器
Socket socket=new Socket ("127.0.0.1",7500 );
//获取Socket流中的输出流,功能:用来把数据写到服务器
OutputStream out=socket.getOutputStream();
//从文件读到客户端
FileInputStream fis=new FileInputStream("E:\\QQwenjian\\1972680739\\FileRecv\\0601.jpg");
//定义字节数组接收文件
byte[] bytes=new byte[1024]; int len=0;
while((len=fis.read(bytes))!=-1){
out.write(bytes,0,len);
}
//客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端,不再读了
socket.shutdownOutput(); //接收服务器端的回复
InputStream in=socket.getInputStream();
len=in.read(bytes);
System.out.println(new String(bytes,0,len));//将字节数组内容转成字符串打印出来
//释放资源
fis.close();
socket.close();
} }
多文件上传案例
只需将服务器端代码封装改一下:
package com.oracle.TCPS; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Random; public class UpLoad implements Runnable{ private Socket socket;
public UpLoad(Socket socket){
this.socket=socket;
}
public void run() {
FileOutputStream fos=null; try{
//显示哪个客户端Socket连接上了服务器
InetAddress ipObject = socket.getInetAddress();//得到IP地址对象
String ip = ipObject.getHostAddress(); //得到IP地址字符串
System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip); //读取文件,明确数据源
InputStream in=socket.getInputStream();
//明确目的地
File file=new File("e:\\JPG");
//判断文件是否存在
if(!file.exists()){
file.mkdirs();//没有则创建文件夹
}
//域名+毫秒值+6位随机数
String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(6)+".jpg";
fos=new FileOutputStream(file+File.separator+filename);
//复制,把Socket输入流中的数据,写入目的地的字节输出流中‘
int len=0;
byte[] bytes=new byte[1024];
while((len=in.read(bytes))!=-1){
fos.write(bytes,0,len);//往服务器端写
}
//回复客户端
OutputStream out=socket.getOutputStream();
out.write("上传成功".getBytes());
}catch (IOException ex){
ex.printStackTrace();
}finally{
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } }
测试类:
package com.oracle.TCPS; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; public class Demo { public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(7500);//明确端口号
while(true){
Socket socket=server.accept();
new Thread(new UpLoad(socket)).start();//匿名内部类 }
} }
等待唤醒机制,UDP通信和TCP通信的更多相关文章
- java之等待唤醒机制(线程之间的通信)
线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同.比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消 ...
- 等待唤醒机制----线程池----lambda表达式
1.等待唤醒机制 1.1线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的 ...
- java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)
1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以 ...
- 多线程之间的通信(等待唤醒机制、Lock 及其它线程的方法)
一.多线程之间的通信. 就是多个线程在操作同一份数据, 但是操作的方法不同. 如: 对于同一个存储块,其中有两个存储位:name sex, 现有两个线程,一个向其中存放数据,一个打印其中的数据. ...
- Java 之 线程 —线程通信( 等待唤醒机制)
一.线程间通信 概念:多个线程在处理同一资源,但是处理的动作(线程的任务)却不相同. 例如: 线程 A 用来生成包子的,线程 B 用来吃包子的,包子可以理解为同一资源,线程 A 与线程 B 处理的动作 ...
- java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)
*java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时 ...
- java-等待唤醒机制(线程中的通信)-线程池
为什么需要线程间的通信 多个线程并发执行时,在默认情况下CPU时随机切换线程的,当我们需要多个线程共同完成一件任务,并且 希望他们有规律的执行,那么多线程之间需要一些协调通信,以此来帮我们达到多线程共 ...
- java多线程(死锁,lock接口,等待唤醒机制)
一.Lock接口 常用方法 Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能. 使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Tic ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
随机推荐
- 浅谈APP消息推送
作为移动端APP产品运营最重要的运营手段,消息推送(push)被越来越多的APP厂商所重视,在信息泛滥的移动互联网时代,手机APP应用安装得越来越多,小小的手机屏幕每天收到的消息推送也越来越多,站在用 ...
- Python 科学工具笔记
Python 科学工具笔记 numpy a = numpy.array([1,2,3,4]);// 创建一个numpy的数组对象 此时a.shape显示的值为(4,); 由此得出结论在一维的数组中, ...
- IIS下发布关于Excel导入导出时遇到的问题集锦(转)
问题描述 1.Excel每个工作薄(sheet)生成记录行数 2.asp.net关于导出Excel的一些问题的集锦 3.下载失败,临时文件或其所在磁盘不可写 4.未能加载文件或程序集“Microsof ...
- [转]javascript之数组操作
javascript之数组操作 .数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个 ...
- 排序 & 常用算法
一.快速排序QuickSort 快速排序和归并排序都使用分治法来设计算法,区别在于归并排序把数组分为两个基本等长的子数组,分别排好序之后还要进行归并(Merge)操作,而快速排序拆分子数组的时候显得更 ...
- xmlDemo4j解析
package lianxi; import java.util.Iterator;import java.util.List;import java.io.File;import java.io.F ...
- js 浮点数计算Bug
之前在写项目时候,直接对带小数点的数据进行运算,发现所得到的值并不是自己想要的. 经过一系列学习后,发现在JavaScript中,浮点数运算都是先转换成二进制,在转成二进制的时候有出现无限循环小数,故 ...
- Python基本操作之文件操作
一. 1.文件操作的函数 open("文件名字(路径)",mode="模式",encoding="字符集") 2.模式:r,w,a,r+,w ...
- Windows和Linux执行Java代码的不同方式
一.Windows 下编译并执行 Java 字节码文件(类文件) 1.编译 Hello.java 源码文件: java -d . Hello.java 2.执行 Hello.class 字节码文件: ...
- three.js学习笔记--基础知识
基础知识 从去年开始就在计划中的three.js终于开始了 历史介绍 (摘自ijunfan1994的转载,感谢作者) OpenGL大概许多人都有所耳闻,它是最常用的跨平台图形库. WebGL是基于Op ...