java知识点总结(全)

io:

根据输入源不同和输出源不同定义了很多io类,还有持有原始类的装饰类给原始类提供额外的功能

文件(file):FileInputStream、FileOutputStream、FileReader、FileWriter

字节数组(byte[]):ByteArrayInputStream、ByteArrayOutputStream

字符数组(char[]):CharArrayReader、CharArrayWriter

缓冲操作:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

对象序列化反序列化:ObjectInputStream、ObjectOutputStream

转换:InputStreamReader,OutStreamWriter

异常:程序出现异常时,不处理的话会走另外一套代码,程序将不会再根据原有计划执行

error,检查异常,非检查异常(runtimeException)

error:系统错误,如资源耗尽,java不会抛出这类错误,除了打印错误信息然后就是停止了

检查异常:在方法签名声明了,使用者必须处理的

非检查异常:一些运行时异常,程序意想不到的异常,使用者可以处理可以不处理

异常处理方式:try catch;throw

只有自己知道怎么处理异常时才捕获处理

finally无论是否有异常,这里面的代码总是会执行,在方法返回前执行

finalize():java垃圾回收对象前会调用对象的finalize()方法,所以你可以自己在这里释放一些特殊的内存(使用本地方法利用c和c++开辟的内存)

异常的限制:异常声明也是方法签名的一部分,重写方法时声明范围只能小不能大,也可以不申明

反射

通Class对象获取构造器,属性,方法等类元素的反射对象,然后利用这些对象对目标类对象进行操作,获取实例,获取注解,执行方法。。。。

获取class对象:类名.class;实例对象.getClass方法;Class.forName("java.lang.Boolean")

泛型:参数化类型,使代码更通用

只存在于编译之前,只适用于编译器检查,提示错误避免向下转型时的错误,虚拟机中并不存在泛型,被擦拭了,换成了上界对象<? extends Number>;

<?>才是所有泛型的父类

spring的泛型注入:spring根据不同的泛型注入不同的类型实例

注解

就是在代码类,方法,成员变量上面添加某些信息,然后再之后使用这些信息

元注解:用于注解注解

使用:使用反射获取到方法或者成员对象上的注解信息,然后再判断信息作出相应的处理

流程控制:

1、if-else;for(foreach);while;do while;break;return;continue;switch

2、return:当前方法退出;break:退出循环;continue:退出当前循环

访问控制:public(所有),protected(子类或包内),default(包内),private(自己)

类的修饰只能是不写(包访问权限)或者public,每个类只能有一个public

其他:接口和抽象类

接口可以多继承,抽象类不行

接口定义方法,不能实现,而抽象类可以实现部分方法。

接口中类成员是static,final的 而抽类象不是的。

当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

内部类

内部类(类的{}里public class test{}),匿名内部类(方法()里new Runnable(){};),局部内部(方法{}里class test{};)

类初始化顺序

继承与初始化(指定初始化值):基类static,子类static,(后面的new子类才能有)基类普通成员初始化,构造器,子类普通成员初始化,构造器

先成员在方法,先静态在非静态,先基类后子类

static在类加载时一次,构造器和普通成员变量初始化,只有在new实例时才进行

面向对象:面向对象的基本特征:继承,多态,封装,抽象

继承:得到父类所有的域和方法

多态:父类引用指向子类对象,但是这个引用可以根据对象正确的调用子类的方法

只能调用父类有的方法,除了被重写的都是调用父类的方法实现

线程:创建,创建方式比较,线程的生命周期

继承Thread类:重写run方法

实现Runnable接口:new Thread(runnable);

实现Callable接口,创建FutrueTask:实现call方法,创建FutrueTask(Callable),new Thread(FutrueTask)(实现了Runnable)

比较:相比1,23避免了单继承,提高了代码的重用性,更适合处理共享资源,123都是通过start开启线程且只能开启一次,run方法只是一个普通的方法而已可重复运行

生命周期:

新建:创建对象

就绪:start()之后进入就绪,得到cpu后到运行

运行:失去cpu进入就绪,sleep,io等待到阻塞,运行完毕,stop到死亡

阻塞:得到io,lock等到就绪,中断到死亡

死亡:线程运行完成

sleep:Thread静态方法阻塞当前线程,不释放锁

wait:object方法,释放锁,阻塞当前线程等待唤醒

join:Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。

yield:使当前线程放弃cpu进入就绪状态

线程中断:中断可以理解为线程的一个标识位属性, interrupt()不会中断一个正在运行的线程,只有阻塞状态的线程才会响应中断信号,抛出中断异常退出、

集合

 

 

实现

线程

大小

空值

顺序

重复

优点

缺点

arralist

数组

不安全

可变

可以

有序

可以

定点查找快

新增删除慢

linkedlist

链表

不安全

可变

可以

有序

可以

新增删除快

定点查找慢

vector

数组

安全

可变

可以

有序

可以

  

stack

数组

安全

可变

可以

有序

可以

  

hashmap

数组+单向链表

不安全

可变

键值都可以

无序

key不可以,值可以

  

treemap

红黑二叉树

不安全

可变

键不行,值可以

有序,会自动排序,key必须继承或者实现comparable或者comparator

key不可以,值可以

排序

 

enummap

枚举专用

       

linkedhashmap

hashmap+双向链表

不安全

可变

键值都可以

有序

key不可以,值可以

有序

 

weakhashmap

数组+单向链表

不安全

可变

键值都可以

无序

key不可以,值可以

  

hashset

hashmap的key

不安全

可变

可以

无序

不可以

  

treeset

treemap的key

不安全

可变

不可以

有序,会自动排序,key必须继承或者实现comparable或者comparator

不可以

排序

 

linkedhashset

linkedhashmap的key

不安全

可变

可以

有序

不可以

有序

 

hashtable

数组+单向链表

安全

可变

键值都不可以

无序

key不可以,值可以

线程安全

 

hashmap实现原理

实现:数组+链表实现

数组存entry对象,entry对象包含:key,value,next,hash是一个单向链表

参数:

初始容量:数组大小,默认16

负载因子:扩容的触发,默认0.75,size到这个值且当前要放的数组有值后扩容2倍

put过程:

计算数组下标:

对key的hashcode值进行二次hash得到h,再对数组长度取模(不直接%,使用二进制运算&来实现的 h & (length-1),length必须为2的次方,如果不是jdk会帮你加大到比你设置数大的最小的一个2次方数)

遍历链表加入:

通过hash值定位到数组下标,取出数组里面的链表,遍历链表判断是否有相同的key(equals方法),有就替换value,没有的话就放在链表最前面

nullkey放在数组0号位置

get过程:

计算数组下标:同上

遍历链表获取:

通过hash值定位到数组下标,取出数组里面的链表,遍历链表判断是否有相同的key(equals方法),有就取出,没有就返回null

扩容过程:

在put时候触发

添加元素的时候判断size是否大于容量*负载因子且需要存放元素的数组已经有值

扩容:遍历原数组元素及链表,重新计算数组下标,存入新数组

添加新元素

1.8新特性:jdk将超过八个长度的链表改成了红黑二叉树实现存储

好处:红黑二叉树采用二分查找算法查找更快,自平衡(一定程度上自平衡,每条路线上黑节点数量相同)保证了时间不会过长(不会超过链表)

hashset就是由hashmap实现的

hashset持有一个hashmap对象,当add object时往map里面放置map.put(object,PRESENT)PRESENT为一个固定的object对象无用

这样,set就是相当于包装了hashmap,只用到map的key就好了

linkedlist实现了deque接口,提供了addFirst,addLast,removeFirst,removeLast等队列双向操作的方法,可以设计先进先出,后进先出队列使用

 

父类

实现

是否是双向队列

是否是阻塞队列

线程

null元素(大都不允许)

容量限制

顺序

concurrent包,在这个包下的一般都线程安全了

arraydeque

deque

数组

双向

非阻塞

不安全

不允许(会抛空指针)

没有限制

有序,按插入顺序

LinkedBlockingDeque

BlockingDeque

链表

双向

阻塞

安全

不允许(会抛空指针)

没限制

有序,按插入顺序

priorityqueue

abstractqueue

数组

队列(fifo)

非阻塞

不安全

不允许(会抛空指针)

没限制

会自动帮你排序(当然你的元素必须可排序)

ConcurrentLinkedQueue

abstractqueue

链表

队列(fifo)

非阻塞

安全

不允许(会抛空指针)

没限制

有序,按插入顺序

DelayQueue

BlockingDeque

数组

队列(fifo)

阻塞

安全

不允许(会抛空指针)

没限制

有序,按插入顺序

SynchronousQueue

BlockingDeque

  

阻塞

安全

不允许(会抛空指针)

没有容量

 

PriorityBlockingQueue

BlockingDeque

数组

队列(fifo)

阻塞

安全

不允许(会抛空指针)

没限制

会自动帮你排序(当然你的元素必须可排序)

LinkedBlockingQueue

BlockingDeque

链表

队列(fifo)

阻塞

安全

不允许(会抛空指针)

没限制

有序,按插入顺序

ArrayBlockingQueue

BlockingDeque

数组

队列(fifo)

阻塞

安全

不允许(会抛空指针)

有界

有序,按插入顺序

java并发控制

java并发内存模型

线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本

原子性:不可分割的一个操作,不能被中断

另一层含义,隔离性,同一时刻只有一个线程对它进行操作

可见性:一个线程对主内存的修改可以及时的被其他线程观察到

顺序性:能保证happen-before

happen-before: a happen-before b, a的操作结果是对b可见的

threalLocal:线程本地变量,每个线程的这个变量值,互不影响,可以互不相同

volatile

可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写

原子性:

对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

volatile写-读建立的happens-before关系

对volatile的写happens-before随后对该变量的读

volatile写-读的内存语义

当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量(所有之前修改的了)值刷新到主内存

当读一个volatile变量时,JMM会把该线程对应的本地内存(所有本地内存)置为无效。线程接下来将从主内存中读取共享变量

atomic:

原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题;具有原子性和可见性(用的value值用的volatile变量)

可见性:由于value值用的是volatile变量

原子性:cas操作

V:内存值 主内存中实时的值java保证,直接看的内存

A:预期值 变量的值,volatile变量保证最新值

B:要修改的新值 要设置为的值

对象+1过程

获取当前内存值赋值给A(volatile int value)

+1获得要修改的值复制给B

进行cas操作,如果成功则跳出循环,如果失败则重复上述步骤。

比较V和A的值,设置V的新值(B)

原子操作:比较V和A的值,设置V的新值

原子保证:unsafe的compareAndSwapInt方法

ABA问题:在线程1获取到B值准备继续时,有两个线程已经一次对V值进行了加一和减一,这时线程1继续也会成功,,这样是不对的(对有些情况比如)

解决方案:加个版本号控制,每次修改内存值得时候增加版本号,比较的时候也比

较版本号

Synchronized:原子性,可见性,有序性

原子性:monitor每个对象都有一个监视器锁,当使用Synchronized关键字时,线程去

执行同步代码的时候回去获取监视器锁,这样其他线程就取不到了,阻塞等待,直到监

视器锁被释放,同步代码执行完就会释放监视器锁

可见性:

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中

当线程获取锁时,JMM会把该线程对应的本地内存置为无效

有序性:对一个锁的解锁,happens-before于随后对这个锁的加锁。

锁的升级与对比(监视器锁)

Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级

锁”,在锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级

锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能

降级

lock:原子性,可见性,有序性

原子性:通过一个队列同步器实现,队列同步器又是通过cas操作实现的,对多个线程提供一个线程安全的状态量,控制多个线程的同步

可见性:同atomic

有序性:对一个锁的解锁,happens-before于随后对这个锁的加锁。

ReentrantLock:互斥锁,可重入

ReadWriteLock:ReentrantReadWriteLock:读不互斥,写互斥

ReentrantReadWriteLock.ReadLock

ReentrantReadWriteLock.WriteLock

公平非公平实现:通过线程排队实现;这个属性锁可设置

Condition接口

任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包

括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与

synchronized同步关键字配合,可以实现等待/通知模式。Condition接口也提供了

类似Object的监视器方法,与Lock配合可以实现等待/通知模式,但是这两者在使用

方式以及功能特性上还是有差别的

 

特性 volatile关键字 synchronized关键字 Lock接口 Atomic变量

原子性 无法保障 可以保障 可以保障 可以保障

可见性 可以保障 可以保障 可以保障 可以保障

有序性 一定程度保障 可以保障 可以保障 无法保障

 

Synchronized和lock比较

实现原理不同

lock是通过代码实现的,synchronized是内置的语言实现

响应中断

Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized

却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断

操作

lock提供了更丰富,灵活的获取锁,释放锁操作,还可设置获取超时

功能

lock提供了更丰富的锁功能:重入锁,读写锁,公平锁。。。

concurrent包

什么是线程安全性?

定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。

正确的行为:和串行调用表现的一模一样,不因多线程而改变

lock

lock接口

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作

可以手动加锁,解锁,重入锁,不可重入锁等等

注意:加锁之后注意解锁,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。

ReadWriteLock接口:

读写锁,读共享,写独占:多个读都可以进来,写进不来;;;写时独占都进不来了包括读

ReentrantLock:

lock的一个实现,一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

重复加锁也需要重复解锁,不然释放不掉

ReentrantReadWriteLock:可重入的读写锁

ReentrantReadWriteLock.ReadLock:嵌套类,提供读锁的获取释放

ReentrantReadWriteLock.WriteLock:嵌套类,提供写锁的获取释放

Condition接口:就相当于object的wait,notify,notifyall的作用

lock.newCondition() 返回绑定到此 Lock 实例的新 Condition 实例。

await() 造成当前线程在接到信号或被中断之前一直处于等待状态。

signal() 唤醒一个等待线程。

signalAll() 唤醒所有等待线程。

atomic部分

提供了很多原子类,提供了很多原子方法

AtomicInteger:原子整型

addAndGet(int delta) 以原子方式将给定值与当前值相加。

compareAndSet(int expect, int update) 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

decrementAndGet() 以原子方式将当前值减 1。

executor部分:线程池相关

提供了很多常见的线程池创建方式

常见线程池:

newCachedThreadPool:可缓存线程池,线程不够就创建,空闲就回收(计时器)核心线程数0,最大线程数int最大值

newFixedThreadPool:固定大小的线程池,核心线程数和最大线程数相同

newSingleThreadExecutor:单线程线程池,保证任务顺序执行

newScheduleThreadPool:定长的线程池,支持定时及周期性任务执行

线程池参数:

corePoolSize(线程池的基本大小)

runnableTaskQueue(任务队列)

maximumPoolSize(线程池最大数量)

ThreadFactory:用于设置创建线程的工厂

RejectedExecutionHandler(饱和策略)

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 默认策略

ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) 

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

线程池处理策略:

请求到来首先交给coreSize内的常驻线程执行

如果coreSize的线程全忙,任务被放到队列里面

如果队列放满了,会新增线程,直到达到maxSize

如果还是处理不过来,会把一个异常扔到RejectedExecutionHandler中去,用户可以自己设定这种情况下的最终处理策略

运行任务

execute()方法用于提交不需要返回值的任务

submit()方法用于提交需要返回值的任务(callable接口任务)

线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完

ExecutorCompletionService:

submit提交任务(callable)

take获取任务结果 future

实现原理:ExecutorCompletionService把执行结果放入一下阻塞队列,take时去队列拿结果,谁先处理完谁先被拿到

 

collections:concurrenthashmap,copyonwritearraylist

concurrenthashmap:线程安全的hashmap

实现原理:使用分段锁技术,实现锁范围的缩小,并发的增大类似于使用多个hashmap(Segment)分段存储,锁的时候只锁一个

get:value值都采用volatile关键字修饰,保证线程间内存可见性

put:锁住其中一个需要修改的hashmap就行了,Segment本身实现了重入锁获取它就行了

查找过程:根据hash值找到Segment(hashmap)数组下标,然后跟hashmap一样了

copyonwritearraylist:

实现原理:通过锁和修改副本去保证线程间读写安全性,写写互斥

get:无锁,直接读

add:操作加锁控制多个线程写,复制一个当前数组副本,向数组添加新数据,list数组引用指向新的数组完成替换

tools:各个工具用途

CountDownLatch:倒数计数器锁

CountDownLatch(int count) 构造一个用给定计数初始化的 CountDownLatch。

await() 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。阻塞

countDown() 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。非阻塞,一个线程可以减多次

用途:线程等待其他线程执行完;一次性使用

Semaphore:信号量与锁很类似,可以看成是一个有限的共享锁,即只能被有限数量的线程使用的共享锁。

Semaphore(int permits) 创建具有给定的许可数的 Semaphore。

acquire() 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,除非线程被中断。可能阻塞

release() 释放一个许可,将其返回给信号量。非阻塞

用途:控制并发数

Exchanger:用于两个线程交换信息使用

Exchanger<String> exchanger = new Exchanger<>();

t1:exchanger.exchange(string)可能阻塞

t2:exchanger.exchange(string)

exchanger.exchange收到两个信息之后会交换同步返回两个信息,不会修改两个线程的原值,当多余两个线程交换时随机组合,多余不足的线程会阻塞可设置超时;同一个线程调用两次也会阻塞

CyclicBarrier:用于多个线程集合等待,然后释放

CyclicBarrier(n)

CyclicBarrier(n,runnable)

await:调用线程等待,直到有n个,执行runnable(由最后一个进入的线程执行),所有线程释放,随即重置

isBroken:是否损坏,任何线程在等待时被中断了,则其他所有线程都将抛出BrokenBarrierException异常,并将barrier置于损坏状态

用途:线程等待

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值