9.集合类
9.1常用的数据结构 数组和链表
9.2数组和链表有什么区别?
数组会在内存当中开辟一块连续的存储空间,需要指定长度
数组当中的每一个元素都有索引,查询的话通过索引可以直接定位到
某一个元素,效率很高,但是进行删除的话,数组会进行移动,
所以效率很低.
链表不需要连续的存储单元,链表中的上一个元素通过指针指向
下一个元素,所以链表结构进行查询的话,头部尾部比较快,
中间元素查找速度比较慢,但是删除的话,只需要删除前后指针,重新
建立指针就可以了,所以删除的性能很高.
9.3 java当中的集合类或集合框架(重点)
collection接口是集合类的顶层接口,collections是工具类
collection有两个子接口,一个list接口,一个是set接口
list接口有序可重复,set接口无序不可重复
list接口常用的实现类有
arrayList 基于数组实现的
linkedList 基于链表实现的 区别参考数组和链表区别
vector 基于数组实现的,但是是线程安全的(synchronized)
copyOnwriteArrayList 复制数组副本来实现的
set接口常用实现类
HashSet 基于hashMap来实现的,实现不可重复是通过 hashCode方法和equals方法进行两次比较,先比较hashCode,再通过equals
TreeSet 基于二叉树来实现的,可以对元素进行排序(排序规则默认是自然顺序,可以自定义比较器,实现自定义排序)
Map接口(key value结构的)-----和class类 类似 private String name;
map接口的实现类
HashMap key不可重复,无序,可以为null
实现原理 基于数组和链表来实现的
当存入一组键值对的时候,先对key进行hash,然后映射到一个初始化长度为16的数组上,当不同的key产生hash碰撞的时候,value会通过链表结构来进行存储,jdk1.8之后对hashMap进行了改进,当链表长度达到临界值8,会通过红黑树来存储value,hashMap有两个参数,一个是初始化数组长度16,负载因子0.75,当满足扩容阈值的时候(当数组的12个元素被存满,并且有hash碰撞了),动态扩容,以2倍的增长方式进行扩容.
HashTable
HashTable是线程安全的hashMap(synchronized机制)key不准许为null
TreeMap基于二叉树来实现的,可对key进行自然排序(自定义比较器,写比较规则)
ConcurrentHashMap是线程安全的,对整个hash桶采用分段策略,拆分成若干个段segment,对每一个段上锁(synchronized),极大的提高了并发修改的效率.
10.线程
10.1进程和线程有什么区别?
进程是指应用程序在运行时的状态,进程会占用系统的cpu以及内存资源
线程是指进程当中的执行流程,多个线程协同工作,会共同使用进程的资源,
才确保进程的功能得以实现.
10.2 java当中如何实现线程呢?
1:继承Thread类
2:实现runnable接口,只是任务类,还需手动创建线程对象
3:线程池机制来创建和管理线程 ThreadPool
singleThreadPool 创建一个线程的线程池
fixedThreadPool 创建固定数量的线程池
cachedThreadPool 数量可缓存的线程池
ScheduledThreadPool 有定时功能的线程池
10.3线程的生命周期
新建状态(new一个线程的时候)
调用线程.start方法的时候,等待cpu分配时间片
可运行状态
当cpu分配到了时间片之后,线程开始运行,运行run方法当中的内容
运行状态
当线程遇到sleep、wait等方法的时候,线程会进入阻塞状态
阻塞状态
当休眠时间到期,或者被notify了,线程又回到了可运行状态
死亡状态
线程运行结束之后,就会销毁,被jvm的gc回收
10.4多线程并发或线程安全问题如何解决?(重点)
1:通过volatile 关键字修饰变量,可以实现线程之间的可见性,避免变量脏读的出现,
底层是通过限制jvm指令的重排序来实现的,适用于一个线程修改,多个线程读的场景
2:通过synchronized锁(任意对象)来实现线程同步,自动锁的思想,
底层实现原理:当有线程进入同步代码块之后,利用jvm的计数器将
锁的标记置为1,当别的线程再想进入的时候,发现锁的标记为1,
该线程就去锁池等待,当第一个线程出来之后,锁的标记会置为0,
之后cpu会随机分配一个线程再次进入同步代码块.
3:通过lock锁的机制,进行手动lock,和unlock,但是这种很容易出现死锁。
注意加锁以及解锁的顺序,就可以避免死锁
4:通过线程安全的集合类,可以解决并发问题
ConcurrentHashMap
CopyonWriteArrayList
5:使用并发包下面的原子类,底层使用的是cas机制(乐观锁),可以解决并发问题 atomicInteger 线程安全的原子整型类
6:使用线程池来创建和管理线程,也可以一定程度上解决并发问题
7:使用ThreadLocal来修饰变量,可以解决并发问题
ThreadLocal底层是怎么实现的?
多个线程会复制一份threadLocao变量的副本进行操作,互不影响,来保证线程安全的
10.5线程之间如何进行通信?
1:使用synchronized锁的wait和notify进行等待和唤醒
2:使用lock锁的condition的await和signal进行等待唤醒
10.6悲观锁和乐观锁
悲观锁的思想对线程并发持悲观态度,使用互斥锁的机制来解决并发问题
乐观锁的思想是使用cas(compareAndSwapper)机制,不上锁,但也能解决并发问题
悲观锁和乐观锁
mysql如何实现悲观锁和乐观锁
1:mysql提供了表锁和行锁的机制,这就是悲观锁的体现
select * from user where id=1 for update
2:mysql没有提供乐观锁的机制,需要自己手动实现
更新user表当真 id=1的username的值
每一条记录都有一个最后一次修改时间,
进行更新操作之前,先把上一次的最后一次修改时间查询出
执行sql语句 update user set username =“新值” where id=1 and
updateTime=上次查询的那个时间
公平锁和非公平锁
公平锁是指线程运行是有序的,FIFO RetrantLock(true)
非公平锁是指线程运行允许插队,具有随机性 RetrantLock(false)
int count=100;
最后一次修改的时间戳或者版本号;
1:先查询一下变量的值以及它的最后一次修改的时间戳;
2:在本地修改变量的值
3:对变量进行修改的时候,先比对一下最后一次修改的时间戳是否发生变化了,如果没发生变化,修改变量的值, 如果发生变化了,重试以上流程
线程的使用场景:
1:项目当中使用线程池(注册完毕发邮件和短信)
2:tomcat本身就是通过线程的机制来处理用户的请求
IO(input输入 output输出)
数据存储的形式
文件形式 类似于湖泊
IO流的形式 类似于河流
File file=new File(“d:\1.txt”);
FileInputStream in=new FileInputStream(“d:\1.txt”);
java当中IO流的分类
字节流 InputStream(抽象类) OutputStream
FileInputStream FileOutputStream (实现类)
装饰者模式对传统的字节流进行了封装,增加了缓冲区功能
BufferedInputStream BufferedOutputStream(带有缓冲区的字节流)
字符流 Reader writer
FileReader FileWriter
BufferedReader BufferedWriter