A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小石姐姐 于 2018-4-26 14:32 编辑

多线程&网络编程&反射

多线程多线程的实现方式
  • 继承Thread类, 重写run方法
  • 实现Runnable接口(仍然是创建Thread类对象), 重写run方法


  • java.lang.Thread类: 实现了Runnable`接口

    • 构造方法

      • Thread Thread(): 创建Thead对象
      • Thread Thread(Runnable r): 通过Runnable对象创建Thread对象
      • Thread Thread(Runnable r, String threadName): 通过Runnable对象创建Thread对象并指定线程名


    • 成员方法

      • void start(): 启动线程, 即让线程开始执行run()方法中的代码
      • String getName(): 获取线程的名称
      • void setName(String name): 设置线程名称


    • 静态方法

      • static Thread currentThread(): 返回对当前正在执行的线程对象的引用
      • static void sleep(long millis): 让所在线程睡眠指定的毫秒




  • 多线程间的同步

    • 共享资源定义位置: 共享资源要定义在多个线程能够共同使用的地方, 如:

      • 多个Thread共用同一个Runnable实现类对象, 则定义为Runnable实现类的非静态成员变量
      • 如果只用Thread子类, 则可以定义为Thread子类的静态成员变量


    • 操作共享数据的线程安全问题: 使用同步解决

      • 同步代码块

        • synchronized (锁对象) {}
        • 锁对象

          • 必须是多个线程共享的对象:

            • 一个类的Class对象
            • 如果是实现Runnable, 则可以是this




      • 同步方法

        • public (static) synchronized void method() {}
        • 锁对象

          • 静态同步方法, 锁对象是: 方法所在类的Class对象
          • 非静态同步方法, 锁对象是: this






线程的生命周期
  • 线程的声明周期中有5种状态

    • 创建: new一个线程对象, 此时还没有调用start()
    • 就绪: 调用start()方法后, 进入就绪状态, 等待CPU执行
    • 运行: 获取了CPU的执行权, 开始运行线程
    • 阻塞: 调用了sleep(), wait(), 或由于IO操作导致阻塞. 阻塞解除后仍会返回就绪状态, 等待CPU执行
    • 销毁: 线程执行完毕



                       +---------------------------+
                       |            阻塞            |
                       +--v----------------------^-+
                          |                      |
                          |解除阻塞          被阻塞|
    new                   |                      |
  +------+             +--v---+               +--^---+               +------+
  |      |   start()   |       >-------------->      |  线程执行结束   |      |
  | 创建  >------------>  就绪 |     CPU调度    | 运行 >---------------> 销毁  |
  |      |             |       <--------------<      |               |      |
  +------+             +------+               +------+               +------+线程之间的通信
  • 使用Object类的成员方法

    • void wait(): 使当前线程处于等待状态, 并且会立刻释放锁
    • void notify(): 随机唤醒一个处于等待状态的线程
    • void notifyAll(): 唤醒所有处于等待状态的线程
    • 注意: 这三个方法必须在同步代码块中, 且只能用锁对象来调用, 否则会抛异常


  • sleep()和wait()的区别

    • sleep

      • 让当前线程在指定时间内睡眠, 时间结束后继续执行
      • 是Thread类的静态方法
      • 不会释放锁


    • wait

      • 让当前线程等待, 直到有人唤醒
      • 是Object类的非静态方法
      • 等待会立刻释放锁



  • 注意:

    • wait的线程必须要有人notify才能唤醒, 如果所有的线程都wait了, 那程序整个就全都在等待了. 所以在写代码时必须考虑仔细


  • 线程释放锁的3种情况

    • synchronized同步代码执行完毕
    • 线程发生了异常导致线程终止
    • 线程调用了wait()方法进行等待, 等待会立刻释放锁



  • 死锁: dead lock

    • 同步代码块中的线程不出来, 也不释放锁; 同步代码块外的线程拿不到锁, 只能等在外面.


  • 发生死锁的原因:

    • 同步代码块内的线程, 可能处在死循环, IO阻塞, sleep()状态, 导致内部持有锁的线程无法出同步代码块
    • 多个线程互相持有锁又不释放锁: 两个线程执行的任务都是双层同步代码块, 每层同步都需要一个锁, 两个线程中同步代码块的锁是相反的


  • 死锁的结果: 程序卡死, 无法继续执行
  • 如何避免死锁:

    • 避免在同步代码块中执行死循环, IO阻塞操作, sleep()
    • 避免多个线程互相持有锁又不释放锁的情况



网络网络通信三要素
  • 传输协议
  • IP地址
  • 端口号


UDP和TCP的区别
  • UDP: USER DATAGRAM PROTOCOL, 用户数据报协议.

    • 特点:

      • 无连接的不可靠协议
      • 数据传输大小限制为64K(一个包)
      • 不需要建立连接即可传输
      • 数据发送速度快, 发送方只发送数据, 不检查接收方是否真正接收到数据, 所以数据可能有丢包的情况


    • 适用场景

      • 适合实时性要求强的场合, 比如网络电话等环境, 这种协议延迟很小



  • TCP: TRANSMISSION CONTROL PROTOCOL, 传输控制协议

    • 特点:

      • 需要建立连接的可靠协议
      • 没有数据传输大小的限制
      • 在传输前需要先建立连接(三次握手)
      • 它的重发机制保证了数据传输的准确性, 但因为需要接收方发回验证信息, 所以数据发送时间长, 数据流量大


    • 适用场景

      • 这种方式适合准确性要求强的场合, 比如金融系统, 视频点播, 用户可以等待数据传输但是不能忍受错误




InetAddress概述和测试
java.net.InetAddress类: 用于表示IP地址对象 (InetAddress的实例包含 IP 地址,还可能包含相应的主机名)
  • 静态方法

    • static InetAddress getLocalHost(): 获取本机的InetAddress对象
    • static InetAddress getByName(String host): 根据主机名IP的字符串获取主机的InetAddress对象
    • static InetAddress getLoopbackAddress(): 获取回环地址的InetAddress对象. 即127.0.0.1或localhost
    • static InetAddress getByAddress(byte[] addr): 根据IP获取InetAddress对象

      • 如: InetAddress.getByAddress(new byte[]{(byte)192, (byte)168, (byte)1, (byte)1});



  • 成员方法

    • String getHostAddress(): 返回主机的IP地址
    • String getHostName(): 返回主机名



UDP协议发送数据
  • java.net.DatagramSocket`类: 基于UDP协议的Socket

    • 构造方法

      • DatagramSocket(): 创建DatagramSocket对象, 随机分配端口号
      • DatagramSocket(int port): 创建DatagramSocket对象, 指定端口号


    • 成员方法

      • void send(DatagramPacket p): 发送数据包
      • void receive(DatagramPacket p): 接收数据, 数据保存在DatagramPacket对象中
      • void close(): 关闭通信, 释放资源



  • java.net.DatagramPacket类: UDP数据包

    • 构造方法

      • DatagramPacket(byte[] msg, int msgLength, InetAddress host, int port): 创建数据包对象, 指定数据, 目标主机对象, 端口
      • DatagramPacket(byte[] buf, int length): 创建数据包对象, 接收数据为length的数据, 存入byte数组中


    • 成员方法

      • InetAddress getAddress(): 获取数据包发送方的InetAddress对象        
      • byte[] getData(): 获取包中的数据, 以byte数组形式
      • int getLength(): 获取数据包中数据的长度, 即byte数组的长度
      • int getPort(): 获取发送方端口号




  
  // 1. 为发送端创建Socket对象(DatagramSocket)
  DatagramSocket datagramSocket = new DatagramSocket();
  // 2. 创建数据并打包
  DatagramPacket datagramPacket = new DatagramPacket(byte数组, 数组长度, InetAddress对象, 端口号);
  // 3. 发送数据
  datagramSocket.send(datagramPacket);
  // 4. 释放资源
  datagramSocket.close();UDP协议接收数据
  • UDP不区分发送端和客户端**, 所以都使用DatagramSocket即可
  • UDP接收数据步骤


  
  // 1. 创建接收端Socket对象:
  DatagramSocket datagramSocket = DatagramSocket(接收方端口号);
  // 2. 接收数据
  DatagramPacket datagramPacket = new DatagramPacket(byte数组, 数组长度);
  datagramSocket.receive(datagramPacket);                 // 该方法会阻塞等待接收数据
  // 3. 解析数据
  InetAddress inetAddress = datagramPacket.getAddress();  // 获取发送方IP地址
  byte[] bytes = datagramPacket.getData();                // 获取数据
  int dataLength = datagramPacket.getLength();            // 获取数据长度
  String s = new String(bytes, 0, dataLength);
  // 4. 输出数据
  System.out.println(s);
  // 5. 释放资源:
  datagramSocket.close();TCP协议发送数据
  • java.net.Socket类: 基于TCP协议的Socket, 作为客户端

    • 构造方法

      • Socket(InetAddress add, int port): 创建TCP客户端对象


    • 成员方法

      • OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
      • InputStream getInputStream(): 获取输入流, 用于接收数据
      • void close(): 释放资源



  • TCP发送数据步骤


  
  // 1. 创建客户端Socket对象(建立连接)
  Socket socket = new Socket(InetAddress地址, 端口号);
  // 2. 获取输出流对象
  OutputStream outputStream = socket.getOutputStream();
  // 3. 发送数据
  outputStream.write(byte数组);
  // 4. 释放资源
  socket.close();TCP协议接收数据
  • java.net.ServerSocket`: TCP服务端

    • 构造方法

      • ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口


    • 成员方法

      • Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
      • void close(): 关闭Socket



  • TCP接收数据步骤


  
  // 1. 创建服务端ServerSocket对象:
  ServerSocket serverSocket = new ServerSocket(端口号);  // 指定要监听的端口号
  // 2. 监听数据
  Socket socket = serverSocket.accept();                // 该方法会阻塞, 直到有客户端连接
  // 3. 获取输入流对象
  InputStream inputStream = socket.getInputStream();
  // 4. 获取数据
  int dataLength = inputStream.read(装数据的byte[]数组);
  String s = new String(byte[], 0, dataLength);
  // 5. 输出数据
  System.out.println(s);
  // 6. 释放资源:
  socket.close();
  serverSocket.close();反射获取字节码对象的3种方法
  • 对象.getClass()
  • 类名.class
  • Class.forName(String fullClassName)


反射使用的相关类和方法
  • java.lang.Class类: 类的字节码对象

    • 获取构造方法

      • Constructor<?>[] getConstructors(): 以数组形式返回该类中所有public的构造方法. 如果没有public的, 则数组长度为0
      • Constructor<?>[] getDeclaredConstructors(): 以数组形式返回该类中所有权限的构造方法, 包括private的. 如果该类是接口, 基本类型, 数组, void, 则数组长度为0
      • Constructor<T> getConstructor(Class<?>... parameterTypes): 根据参数列表返回指定的public的构造方法. 参数列表填写参数的字节码对象
      • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 根据参数列表返回指定的所有权限的构造方法, 包括private的. 参数列表填写参数的字节码对象


    • 获取成员属性

      • Field[] getFields(): 获取所有public的成员变量
      • Field[] getDeclaredFields(): 获取所有权限的成员变量, 包括private的
      • Field getField(String fieldName): 通过指定的成员变量名获取指定的public的成员变量
      • Field getDeclaredField(String fieldName): 通过指定的成员变量名获取指定的所有权限的成员变量, 包括private的


    • 获取成员方法

      • Method[] getMethods(): 返回所有public的方法数组
      • Method[] getDeclaredMethods(): 返回所有权限的方法数组
      • Method getMethod(String name, Class<?>... parameterTypes): 获取public的方法, 传入方法名和方法形参字节码对象
      • Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取所有权限的指定方法, 传入方法名和方法形参字节码对象


    • 创建对象

      • T newInstance(): 使用该类的无参构造创建一个对象



  • java.lang.reflect.Constructor类: 构造方法对象

    • T newInstance(): 通过无参构造方法对象创建一个类的对象
    • T newInstance(Object... initargs): 通过有参构造方法对象创建一个类的对象, 传入构造方法所需的参数列表
    • void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的构造方法


  • java.lang.reflect.Field类: 成员变量对象

    • Object get(Object obj): 获取指定对象的属性值
    • void set(Object obj, Object value): 将指定对象的属性值设置为指定的值
    • void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的成员属性


  • java.lang.reflect.Method类: 成员方法对象

    • Object invoke(Object obj, Object... args): 调用指定对象的成员方法
    • void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的成员方法



JavaBean
  • 作用: 用于封装和存储数据
  • 规范

    • 类必须是public修饰的
    • 成员变量必须是private的
    • 必须有public的set/get方法
    • 至少提供一个无参构造方法
    • 实现Serializable接口(当对象需要通过IO流传输时)



BeanUtils工具类
BeanUtils类常用的3个方法
  • static void setProperty(Object bean, String name, Object value): 给JavaBean对象的成员属性赋值, 传入对象, 成员属性名, 属性值
  • static String getProperty(Object bean, String name): 获取JavaBean成员属性的属性值, 传入对象, 成员属性名, 返回属性值的字符串形式
  • static void populate(Object bean, Map properties): 给JavaBean对象的成员属性赋值, 传入对象, Map的key是属性名, value是属性值







0 个回复

您需要登录后才可以回帖 登录 | 加入黑马