面向对象高级9

1.多线程

概念:

1.并发和并行:

  • 并行: 两个任务真的是同时执行的
  • 并发: 两个任务是交替执行的
  • 总结:java是基于并发

2.进程和线程:

  • 进程: 其实就是系统为程序匹配的内存空间,有一个编号,这个编号称为进程id,并没有指定代码的能力
  • 线程: 是进程中的工作单元,是用来执行代码的
  • 结论:我们的代码都是线程执行的

创建方式:

第一种:

  1. 定义一个类去继承Thread的类
  2. 重写run方法
  3. 将你要执行的代码放到run方法中
  4. 创建线程的子类对象
  5. 调用对象的start方法进行线程的开启

第二种:

  1. 定义一个类实现Runnable接口
  2. 重写run方法
  3. 将你要执行的代码方法run方法中
  4. 创建Runnable的实现类对象
  5. 创建Thread对象,将Runnable的实现类传递进来
  6. 调用Thread的start开启线程

两者对比:

1.继承方式:

  • 优点:可以直接使用Thread中的功能
  • 缺点:因为java是单继承,这个类不能在继承其他的类了,比较死板,代码和线程绑定比较紧密,不灵活

2.实现方式:

  • 优点:一个类实现接口的时候,还可以继承其他的类,比较灵活,可以将任何和线程分离
  • 缺点:他不能直接使用Thread中的功能,但是可以弥补,用static Thread currentThread(); 返回正在执行代码的当前线程

交替执行的原因:

  • 因为每开启一条线程,就会出现一个独立的栈空间,cup切换就是栈空间的代码,所以多个栈空间的代码出现了交替执行的现象,根本原因是cpu随机切换导致的

注意事项:

  1. 线程从哪里跌倒,就从哪里爬起来
  2. start方法才是真正开启线程的方法,因为底层调用了native的本地方法start0,run只是一个普通的方法,我们调用start方法的时候,底层会自动帮我们调用run方法

1.2 Thread

构造:

  • Thread(Runnable r); 创建线程并设置任务
  • Thread(Rannanle r, String name); 创建线程并设置任务,给线程起名字

功能:

  1. void start(); 开启线程,执行线程任务!
  2. setName(String name); 设置线程名字
  3. String getName(); 获取名字
  4. static Thread currentThread(); 返回正在执行代码的当前线程
  5. static Thread sleep(long time); 让当前线程处于睡眠状态,单位时间为毫秒
  6. void setPriority(int value ) 设置线程的优先级,[1,10], 其中默认值为5
  7. setDaemon(boolean true) 一定要开启线程之前的设置,让当前线程作为守护线程,守护其他所有非守护线程

多线程存在的问题:当多个线程操作共享数据的时候,会出现线程安全问题

解决方案:

1.通过同步代码块解决

synchronized(锁对象){
    这里放置 ---> 需要被一条线程执行完其他线程才能进来的代码

}

注意事项: 锁对象可以是任何引用数据类型,  但是一定要保证锁对象唯一, 否则出现从后面进的情况!!!!!!!!!

2.通过同步方法解决(不推荐!!!!!!)

缺点:

1.锁对象是固定死的,普通的成员方法是this,静态的成员方法时当前类的字节码对象

2.要锁就将整个方法的代码都锁起来了!!!!!无法锁定部分代码!!!!!

同步方法的类都被淘汰了

Vector    ArrayList集合的前身

Hashtable   HashMap

3.注意点:

  • ArrayList , HashMap, StringBuilder都是线程不安全!!!!!!
  • Collections.synchronizedXxx的方法可以将不安全的集合变成安全的集合,就是给原有集合的所有的方法加上了同步代码块!!!!
  • StringBuffer线程安全, 和StringBuilder用法完全一样!!!!!!!!

3.jdk1.5的Lock锁机制

Lock lock = new ReentrantLock();

lock();和unlock();

缺点:

1.需要自己维护锁,必须保证锁对象唯一。

2. unlock最好放到finally里面, 如果不放在这里一旦出了异常, 没有释放锁, 这个空间就锁死了!!!!!

4.线程间通信

5.线程的状态

  • NEW 创建线程对象, 但是还未调用start方法
  • RUNNABLE 线程对象已经调用完了start方法, 具备被cpu扫描到的资格的状态
  • BLOCKED 线程正在被cpu执行, 但是遇到锁, 进不去的状态!!!!!
  • WAITING 线程遇到wait方法, 处于无限等待, 只能被notify或者notifyAll唤醒
  • TIMED_WAITING 线程遇到了sleep(long time), wait(long time), 处于计时等待
  • TERMINATED 线程任务执行完后, 线程消亡的状态

6.线程池

作用: 解决我们频繁创建线程以及销毁线程的过程, 节约了资源以及提高的程序的运行效率, 创建线程比较耗费时间的.

第一种:

  • 造出的池子默认没有线程, 我们提交任务, 如果没有线程, 他会自动帮我们创建线程, 然后执行任务, 我们省力, 我们不用再关系创建线程的动作, 被线程池管理了
  • Executors 的 static ExecutorService newCachedThreadPool()  
  • 总结: 后期用的比较少, 因为线程的数量没有限制, 可能会造成后期线程数据过多, 导致cpu压力过高!!!!!

第二种:

  • static ExecutorService newFixedThreadPool(int nThreads)  
  • 刚开里面也是空的, 但是他设置上限, 缺点: 不能够控制闲时和忙时的线程数量, 以及没有拒绝策略

第三种(一般写5个参数就可以,剩余两个默认):

  • ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 
    • 参数一  核心数量
    • 参数二  最大数量
    • 参数三  临时的销毁的默认时间
    • 参数四  时间的单位 TimeUtil枚举类有各种时间单位
    • 参数五  任务队列 LinkedBlockingQueue  链表阻塞队列   ArrayBlockingQueue集合阻塞队列
    • 参数六  Excutors.defaultThreadFactory()
    • 参数七  拒绝策略
      • new ThreadPoolExecutor.AbortPolicy()多余的任务丢弃掉, 并抛出异常
      • new ThreadPoolExecutor.DiscardPolicy()多余的任务丢弃掉, 不抛出异常
      •  new ThreadPoolExecutor.DiscardOldestPolicy()多余的任务将等待最久丢弃掉
      • new ThreadPoolExecutor.CallerRunsPolicy()如果有多余不抛弃, 让其他线程来执行!!!!!

功能:

  • submit(Runnable r) 向线程池中提交任务, 并且执行
  • shutdown() 关闭线程池,以后绝对不会用, 项目下线了, 服务器停止了!!!!!!(一般不手动关闭)

2.网络编程 

作用: 实现网络中设备和设备之间数据的收发

概念:ip、端口和协议

ip:

  • IPV4
    • 由32个二进制组成, 最多40个亿
    • 192.168.11.225
    • 公网ip 一级IP(42个亿公网IP)
    • 只有公网IP才能真正实现网络数据传输!!!!!!,  只有公网IP在公用网络中才能找到他
    • 小命令 ipconfig  显示本机的ip相关的信息     127.0.0.1 代表本机地址!!!!!!
    • InetAddress   static InetAddress getByName(ip地址的字符串| 主机名);建议大家传入IP地址, 因为主机名不唯一
  • IPV6
    • 由128个二进制组成, 但是现在ipv4还是主流

端口:

本质: 是程序在设备中的编号, 他的范围是[0, 65535], 0-1024之间不建议大家使用否则会先端口被占用的风险

协议:

1.UDP:

面向无连接, 速度快, 可能会丢失数据

  • DatagramSocket
    • 构造
    • DatagramSocket()创建UDP的程序, 但是端口随机
    • DatagramSocket(int port)创建UDP的程序, 指定端口
  • 功能
    • send(DatagramPacket dp);发送数据
      • DatagramPacket
      • DatagramPacket(byte[] arr, int length);用于接受数据的包
      • DatagramPacket(byte[] arr, int length,InetAddress address,int port);用于发送数据的包
    • receive(DatagramPacket dp);接受数据
    • void close();关闭资源, 底层使用的是io流技术实现的

2.TCP:

面向连接, 速度稍慢, 不会丢失数据

客户端Socket

用来创建客户端的TCP

  • 构造
    • Socket(String ip, int port)  创建Socket链接指定ip, 指定端口的服务器
  • 功能
    • InputStream getInputStream(); 获取听筒
    • OutputStream getOutputStream(); 获取话筒。
    • void close();  关闭资源
    • shutdownOutput();  关闭话筒

服务器ServerSocket

  • 构造
    • ServerSocket(int port) 启动服务器程序, 并且设置端口
  • 功能
    • Socket accept(); 监听客户端链接, 一旦有链接则创建Socket为其服务
  • 注意:
    • 1. ServerSocket的accept方法是阻塞方法, 如果没有客户端链接, 则一直处于等待
    • 2. 网络流所有的read方法都是读的方法都是阻塞方法, 如果结束不到结束标记或者数据就会一直等待

3.扩展

 3.1 PrintStream

概念: 字节打印流, 本质就是一条输出流, 不过提供了特殊的方法

  • 构造
    •  PrintStream(String fileName)  创建打印流, 指向指定文件
    •   PrintStream(OutputStream out)  创建打印流, 指向其他输出流的目的地
  • 功能
    • write相关的方法  用来写字节数据
    • println相关的方法  用来写基本类型以及字符串数据, 而且自动写换行符!!!!!!
    • close  关闭资源.
  • 特点:既可以写字节数据, 也可以写字符数据, 经常用于即时通信技术!!!!!其他地方比较少见

3.2 UUID

作用:  产生36位不重复的字符串

  • 功能
    • UUID randomUUID();
    • String toString(); 得到随机的字符串

3.3位运算

  • >>
    • 将整数变成二进制, 右移几位, 前面补0
  • &
    • 遇0则0,一个数 & 15 结果的范围是4个二进制 , 本质 就是[0,15]之间
  • ^
    • 相同为0, 不同为1
  • 文件夹小算法
    • 作用: 一般用于大量文件存储的时候, 为了提高文件的访问速度, 需要将文件存放到多级文件夹中

     

4.log日志

logback的使用

  • 1.将jar包拷贝到当前模块下的lib目录中
  • 2.右键 ----> add as lib......展开jar包!!!!!!到当前模块的环境中
  • 3.将配置文件放到 src下面
  • 4.创建核心对象打印日志 
    • private static final Logger LOGGER = LoggerFactory.getLogger(Test1.class);
  • 5.使用他的功能来输出日志  debug  info  error  xxxx

日志的级别大小

all  trace  debug  info  warn  errer  fatal  off

好处:

  • 1.可以通过配置文件控制日志的输出,不需要改动原码!!!!!!
  • 2.可以将日志持久化存储

注意:只会输出 >=   配置的级别的日志!!!!!! 

5.单例设计模式

作用: 保证一个类有且只能创建一个对象

使用场景: 可以用来共享数据

实现方式:

方式1 : 程序员式

  •  1.私有化构造
     2.维护一个public final static 本类对象
     3.通过类名.对象名

public class Person {
    //私有化构造函数!!!!!
    private Person(){}
    //必须在本类中想办法调用构造造一个对象
    public final static Person person = new Person();
    
}

方式2: 饿汉式

  •    1.私有化构造
       2.维护一个private static 本类对象
       3.提供一个public 静态的方法返回本类对象
       4. 类名.静态方法获取本类对象

public class Person1 {
    //私有化构造函数!!!!!
    private Person1(){}
    //必须在本类中想办法调用构造造一个对象
    private  static Person1 person = new Person1();

    //提供一个公共静态的方法返回该对象
    public static Person1 getInstance(){
        return person;
    }
    
}

方式3: 懒汉式(延时加载)

  •  1.私有化构造
     2.维护一个private static 本类引用
     3.提供一个public 静态的方法返回本类对象,方法体中判断对象是为null, 如果为null创建对象
     4. 类名.静态方法获取本类对象

public class Person2 {
    //私有化构造函数!!!!!
    private Person2() {
    }

    //必须在本类中想办法调用构造造一个引用
    private static Person2 person;

    //提供一个公共静态的方法返回该对象
    public synchronized static Person2 getInstance() {
        if (person == null) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            person = new Person2();
        }
        return person;
    }
}

 问题:多线程访问可能出现线程安全问题

解决:给方法加锁

6.类加载器

作用:

1.帮我们将硬盘上的字节码文件加载到内存中,jvm自动帮我们做的, 我们只需要理解

2.可以读取字节码路径下的东西(掌握, 需要能够加载字节码路径自己的文件!!!!!)

步骤:

  • 1.获取类加载器
    • ClassLoader cl =  当前类.class.getClassLoader();
  • 2.使用类加载的功能
    • 1. InputStream  getResourceAsStream(String path);  以流的方式,关联字节码路径下的 "path"所对应的文件
    • 2. URL  getResource(String path);  以URL的方式,关联字节码路径下的 "path"所对应的文件
      • URL 统一资源定位符,内置动态获取的绝对路径
        • String getPath();  得到绝对路径

类加载的分类:

  • bootstrap classloader(启动类加载器)  
    • 平台类加载器, 加载一些底层的非常核心的东西, 不是java语言写的, 是c++语言写的, java强行获取这个类加载的话, 会得到null, 加载java以外的东西!!!!!
  • platform classloader(平台类加载器)
    • 加载大部分的jdk的扩展包的字节码文件, 以及少量特殊的JDK的类
  • system classloader(系统类加载器)
    • 负责加载大部分的jdk的类,以及程序员自己写的类
  • 双亲委派模型
    • 其实就是一种询问机制,  保证一个类只会被加载一次!!!!!!!!!

7.反射

1.反射第一步:

得到你要操作的类的字节码对象: 

  1. Class Class.forName(全类名);  全类名 = 包名 + 类名
  2. 类名.class
  3. Class c = 对象.getClass();

2.创建对象

  • 1.先拿到构造函数
    • Constructor[] getConstructors(); 获取所有的public修饰的构造函数
    • Constructor[] getDeclaredConstructors();  获取所有构造函数, 包含私有的
    • Constructor getConstructor(Class ... args);  根据参数类型, 获取指定的构造,只能获取public修饰的
    • Constructor getDeclaredConstructor(Class ... args);  根据参数类型, 获取指定的构造, 可以获取任何修饰符修饰的构造
  • 2.通过构造函数创建对象
    • Constructor
      • T    newInstance(Object ... args);
      • void setAccessable(boolean isForce)  true,false(默认值)
      • 注意事项:
        • 私有的构造必须设置暴力反射才行
        • 简化的方式只适用于public修饰的无参构造
    • 简化方式
      • 类名 对象名 = 字节码对象.newInstance();

3.使用成员变量

  • 1.先获取到成员变量对象
    • Field[] getFields();  获取所有的public修饰的构造函数
    • Field getField(String name);  根据参数类型, 获取指定的构造,只能获取public修饰的
    • Field[] getDeclaredFields();  获取所有构造函数, 包含私有的
    • Field getDeclaredField(String name);  根据参数类型, 获取指定的构造, 可以获取任何修饰符修饰的构造
  • 2.使用成员变量
    • Field
      • set(对象,实际参数)  给对象的成员变量设置值
      • Object get(对象)  获取对象上的成员变量的值
    • 静态的成员变量不需要对象
      • set(null,实际参数)  第一个参数传入null就行

4.使用成员方法

  • 1.先获取到成员方法对象
    • Method[] getMethods();  获取所有的public修饰的构造函数
    • Method[] getDeclaredMethods();  获取所有构造函数, 包含私有的
    • Method getMethod(String name,Class ... args)
      •  根据参数类型, 获取指定的构造,只能获取public修饰的
    • Method getDeclaredMethod(String name,Class ...args );  
      • 根据参数类型, 获取指定的构造, 可以获取任何修饰符修饰的构造
  • 2.调用方法
    • Method
      • Object invoke(对象, 实际参数);  
        • 反射执行方法, 如果方法的返回值类型为void的话, 返回null
    • 静态的方法不需要对象 
      • Object invoke(null, 实际参数);
        • 第一个参数传入null就行

8.枚举

JDK1.5出现的技术, 用来表示选项, 这些选项的特点是 不能进行数学运算,  因为他是引用数据类型, 本质就是一个类!!!!!!!!,类中可以定义的内容, 枚举中都可以定义,但是我们一般不会定义其他内容, 因为他的作用决定他的使用场景!!!!

定义格式:

  • public enum 枚举名{
        枚举项1, 枚举项2 .......

    }

作用:

  • 用来表示选项的,这些可以避免一些基本数学运算导致变量。

注意事项:

  •   1.构造必须被private修饰, 如果我们不给构造, 系统会默认给定private 修饰的无参构造
  •  2.如果你手动给了有参构造, 则不会在赠送的无参构造,需要显示调用你的有参构造
  • 3.枚举项必须在第一行有效语句
  •  4.如果枚举项下面没有东西了, 最后的分号可以省略, 如果有内容则不能省略,建议不要省!!!!!!
  •  5.枚举中可以出现抽象方法, 但是枚举项需要使用匿名内部类的方式创建抽象类的子类!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值