Java学习(流专栏附一些Java进阶内容)

在这里插入图片描述
从数据来源或者说是操作对象角度来看,IO类可以分为:

  • 1、文件(file): FileInputStream 、 FileOutputStream 、 FileReader、
    FileWriter
  • 2、数组([]):
  • 2.1、 字节数组(byte[]):ByteArrayInputStream、ByteArrayOutputStream
  • 2.2、字符数组(char[]):CharArrayReader、CharArrayWriter
  • 3、管道操作:PipedInputStream、PipedOutputStream、PipedReader、PipedWrited
  • 4、基本数据类型:DataInputStream、DataOutputStream
  • 、缓冲操作:BufferedInputStream、BufferdOutputStream、BufferdReader、BufferedWriter
  • 6、打印:PrintStream、PrintWriter
  • 7、对象序列化反序列化:ObjectInputStream、ObjectOutputStream
  • 8、转换:InputStreamReader、OutputStreamWriter

从数据传输方式或者说是运输方式角度看,可以将IO类分为:

  • 1、字节流
  • 2、字符流
    字节流是以一个字节单位来运输的,比如一杯一杯的取水。而字符流是以多个字节来运输的,比如一桶一桶的取水,一桶水又可以分为几杯水。

字节流和字符流的区别:
字节流读取单个字节,字符流读取单个字符(一个字符根据编码的不同,对应的字节也不同,如UTF-8编码是3个字节,中文编码是2个字节。)字节流用来处理二进制文件(图片、MP3、视频文件),字符流用来处理文本文件(可以看作是特殊的额二进制文件,使用了某种编码,人可以阅读)。简而言之,字节是给计算机看的,字符才是给人看的。
在这里插入图片描述

IO类和相关方法
IO类虽然很多,但最基本的是4个抽象类:InputStream、OutputStream、Reader、Writer。最基本的方法就是读read()方法,写write()方法。方法的具体实现要看继承者四个抽象类的子类。我们平时使用的也是子类对象。这些类中的一些方法都是(native)本地方法,所以没有Java源代码。

InputStream类
在这里插入图片描述
在这里插入图片描述

OutputStream类
在这里插入图片描述

Reader类
在这里插入图片描述

Writer类
在这里插入图片描述

使用多线程的目的是更好的利用Cpu资源。

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程

  • 并行与并发:

  • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

  • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
    /*
    QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
    TPS:是Transactions Per Second的缩写,也就是事务数/秒。它是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。
    */

  • 线程安全:经常用来秒回一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不会影响任何结果。在这个时候使用多线程,我们只需要关住系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果。

  • 同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的尊去。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。

线程状态:
在这里插入图片描述

线程状态转换:
1.调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
2.调用wait(),使该线程处于等待池(wait blocked pool),知道notify()/notifyAll(),线程被唤醒放到锁定池(lock blocked pool),释放同步锁线程回到可运行状态(Runnable)
3.对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool),同步锁被释放进入可运行状态(Runnable)
此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让每一个running状态的线程转入runnable。

Synchronized,wait,notify是任何对象都具有的同步工具。
在这里插入图片描述
Monitor
他们是应用于同步问题的人工线程调度工具。讲其本质,首先要明确monitor的概念,Java的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronize范围内,监视器发挥作用。
Wait/notify必须存在于synchronize块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。
当某代码并不持有监视器的使用权时,(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.illegalMonitorStateException。也包括在synchronize块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。

Volatile
多线程的内存模型:main memory(主存)、working memory(线程栈)、在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)
在这里插入图片描述

针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后再某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。

基本线程类:
基本线程类指的是Thread类,Runnable接口,Callable接口

Thread类相关方法:
Thread类的相关方法:
//当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)
Thread.yield()
//暂停一段时间
Thread.sleep()
//在一个线程中调用other.join(),将等待执行完后才继续本线程
Join()
//后两个函数皆可被打断
Interrupt()

关于中断:
它并不像stop方法那样会中断一个正在运行的线程。线程会不时地检测中断标志位,以判断线程是否应该被中断,中断只会影响到wait状态、sleep状态和join状态。被打断的线程会抛出InterruptedException。
Thread.interrupted()检查当前线程是否发生中断,返回boolean
Synchronize在获锁的过程中是不能被中断的。

中断是一个状态!Interrupt()方法只是将这个状态置为true而已。所以说正常运行的程序不去检测状态,就不会终止,而wait等阻塞方法会检查并抛出异常。如果在正常运行的程序中添加while(!Thread.interruptd()),则同样在中断后离开代码体。

Runnable
与Thread类似

Callable
Future模式:并发music的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态。
在这里插入图片描述

高级多线程控制类
1.ThreadLocal类
用处:保存线程的独立变量。对一个线程类(继承自Thread)
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。
实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。
主要的方法是get()和set(T a),set之后再map里维护一个threadLocal->,get时将a返回。ThreadLocal是一个特殊的容器。
2.原子类(AtomicIntegr、AtomicBoolean…)
如果使用atomic wrapper class如atomicInteger,或者使用自己保证原子的操作,则等同于synchronize

在这里插入图片描述

该方法可用于实现乐观锁,考虑文中最初提到的如下场景:a给b付款10元,a扣了10元,b要加10元。此时c给b2元,但是b加十元代码约为:
在这里插入图片描述
AtomicReference
对于AtomicReference来讲,也许对象会出现,属性丢失的情况,即oldObject==current,但是OldObject.getPropertyA != current.getPropertyA。

3.Lock类
Lock:在java.util.concurrent包内。共有三个实现。
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
主要目的是和synchronize一样,两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。
lock更灵活,可以自由定义多把锁的加锁解锁顺序(synchronized要按照先加的后解顺序)
提供多种加锁方案,lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, 还有trylock的带超时时间版本。
本质上和监视器锁(即synchronized是一样的)
能力越大,责任越大,必须控制好加锁和解锁,否则会导致灾难。
和Condition类的结合。
性能更高,对比如下图:
在这里插入图片描述
Synchronize和Lock的性能对比

ReentrantLock
可重入的意义在于持有锁的线程可以继续持有,并且要释放对等的次数后才真正释放该锁。
使用方法是:
1.先new一个实例
Static ReentrantLock r = new ReentrantLock();
2.加锁
r.lock() 或r.lockInterruptibly();
此处也是个不同。当a线程lock后,b线程阻塞,此时如果是lockInterruptibly,那么在
调用b.interrupt()之后,b线程退出阻塞,并放弃对资源的争抢,进入catch块。(如果使用后者,必须throw interruptable exception 或catch)
3.释放锁
r.unlock()
必须做!要放在finally中,以防止异常跳出了正常流程,导致灾难。这里补充一个小知识点,finally是可以信任的:经过测试,哪怕是发生了OutofMemoryError,finally中的语句执行也能够得到保证。
ReentrantReadWriteLock
可重入读写锁(读写锁的一个实现)
ReentrantReadWriterLock lock = new ReentrantReadWriterLock()
ReadLock r = lock.readLock()
WriteLock w = lock。WriteLock()
两者都有lqock,unlock方法。写写,写读互斥;读读补互斥,可以实现兵法读的高效线程安全代码。
4.容器类
常用的两个:BlockingQueue、ConcurentHashMap
BlockingQueue
阻塞队列。该类是java.util.concurrent包下的重要类,通过对Queue的学习可以得知,这个queue是单向队列,可以在队列头添加元素和在队尾删除或取出元素。类似于一个管道,特别适用于先进先出策略的一些应用场景。
BlockingQueue在队列基础上添加了多线程协作的功能。
在这里插入图片描述
除了传统的queue功能(表格左边的两列)之外,还提供了阻塞接口put和take,带超时功能的阻塞接口offer和poll。Put会在队列满的时候阻塞,知道有空间时被唤醒;take在队列空的时候阻塞,直到有东西拿的时候才被唤醒。
常见的阻塞队列有:
ArrayListBlockingQueue、LinkListBlockingQueue、DelayQueue、SynchronousQueue

5.管理类
管理类的概念比较泛,用于管理线程,本身不是多线程,但提供了一些机制来利用上述的工具做一些封装。
ThreadPoolExecutor
如果不了解该类,应该先了解ExecutorService。开启自己的线程池十分方便。
ExecutorService e = Executors.newCachedThreadPool();
ExecutorService e = Executors.newSingleThreadExecutor();
ExecutorService e = Executors.newFixedThreadPool(3);
// 第一种是可变大小线程池,按照任务数来分配线程,
// 第二种是单线程池,相当于FixedThreadPool(1)
// 第三种是固定大小线程池。
// 然后运行
e.execute(new MyRunnableImpl());
该类内部是通过ThreadPoolExecutor实现的,掌握该类有助于理解线程池的管理,本质上,他们都是ThreadPoolExecutor类的各种实现版本。

Java 高级特性-反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
用途:在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的的私有成员或是方法。当然,也不是所有的都适合反射。对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

反射机制的相关类
与Java反射相关的类如下:
在这里插入图片描述

Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍

  • 获取类相关的方法
    在这里插入图片描述
  • 获得类中属性相关的方法

在这里插入图片描述

  • 获得类中注解相关的方法
    在这里插入图片描述
  • 获得类中构造器相关的方法
    在这里插入图片描述
  • 获取类中方法相关的方法
    在这里插入图片描述
  • 类中其他重要的方法
    在这里插入图片描述
    Filed类
    Field代表类的成员变量(成员变量也称为类的属性)
    在这里插入图片描述

Method类
Method代表类的方法
在这里插入图片描述

Constructor类
Constructor代表类的构造方法
在这里插入图片描述

发布了16 篇原创文章 · 获赞 4 · 访问量 327

猜你喜欢

转载自blog.csdn.net/qq_39197781/article/details/104569498
今日推荐