等待唤醒机制,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();//匿名内部类

        }
    }

}

原文地址:https://www.cnblogs.com/lzw123-/p/9559078.html

时间: 2024-11-13 10:02:28

等待唤醒机制,UDP通信和TCP通信的相关文章

java之等待唤醒机制(线程之间的通信)

线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同.比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题. 为什么要处理线程间通信: 多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据. 如何保证线程间通信有效利

等待唤醒机制

等待唤醒机制 1.1 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题. 为什么要处理线程间通信: 多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据.

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

多线程之间的通信(等待唤醒机制、Lock 及其它线程的方法)

一.多线程之间的通信. 就是多个线程在操作同一份数据, 但是操作的方法不同. 如: 对于同一个存储块,其中有两个存储位:name   sex, 现有两个线程,一个向其中存放数据,一个打印其中的数据. 为了解决上述问题中的安全问题(在存放线程进行存放操作的时候, 打印线程不能对共有数据进行操作),所以应当对两个线程       操作共有数据的代码部分进行同步(使用synchronized(),来进行同步, 注意 :使用同一个对象作为同步锁. 二.等待唤醒机制. 在上述案例实现过后运行,会发现:打印

【线程间通信:等待唤醒机制】

在线程安全解决之后,还是一样存在着如下的问题: A:如果消费者先抢到CPU的执行权,就会去消费数据,但是现在的数据是默认值,没有意义,应该等着数据有意义,再消费. B:如果生产者先抢到CPU的执行权,就会去生产数据,但是呢,它生产完数据后,还继续拥有执行权,它又继续产生数据.这是有问题的,它应该等着消费者把数据消费掉,然后再生产. 正常的思路: A:生产者:先看是否有数据,有就等待,没有就生产,生产完后通知消费者来消费数据. B:消费者:先是是否有数据,有就消费,没有就等待,通知生产者生产数据.

线程间通信——等待唤醒机制

线程间通信——等待唤醒机制,避免争夺同一资源: 锁对象可以是任意Object类的子类对象: 包子案例: 包子案例——生产者和消费者: 代码实现: 关键就是在于两个线程使用同一个锁对象! 这边是主程序调用这两个线程时候传入的同一个对象! 包子铺线程类——生产者: 其中,baozi类作为成员变量,并且重载了带参的构造方法: 锁对象为调用包子铺带参的构造方法传入的这个包子变量bz; 调用点wait方法必须是锁对象调用,锁对象调用wait方法之后当前线程就进入等待状态,另外一个线程此时应该是正在执行:

等待与唤醒机制(线程之间的通信)

线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 为什么要处理线程间通信 多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们 希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据. 如何保证线程间通信有效利用资源: 多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作. 就是多个线程在操作同一份数据时, 避免对同一共享变量的

线程间的通信--等待唤醒机制

1.多个线程操作相同的资源,但是操作动作不同,所以存在安全问题例如: public class Test { public static void main(String[] args) { Resource r = new Resource(); Input in = new Input(r); Output out = new Output(r); Thread tin = new Thread(in); Thread tout = new Thread(out); tin.start();