Collection : 集合层次的跟接口
List : 有序 有下标 可重复
- ArrayList:底层结构是数组,内存空间是连续的 常用于下标 *** 作,查询较快 - linkedList:底层结构是链表,内存空间是不连续的 常用于首尾 *** 作,增删较快
Set : 无序 无下标 不可重复,常用于去重
-
Map : 键值对, key&value,
Map.Entry<,>
-
map中的key不允许重复,value可以重复
-
HashMap
-
结构是数组+链表 或者 数组+红黑树 的形式
-
HashMap底层的Entry[ ]数组,初始容量为16,加载因子是0.75f,扩容按约为2倍扩容
-
存放数据时,会根据hash(key)%n算法来计算数据的存放位置,n就是数组的长度,其实也就是集合的容量
-
当计算到的位置之前没有存过数据的时候,会直接存放数据
-
当计算的位置,有数据时,会发生hash冲突/hash碰撞
解决的办法就是采用链表的结构,在数组中指定位置处以后元素之后插入新的元素
也就是说数组中的元素都是最早加入的节点
-
如果链表的长度>8且数组长度>64时,链表会转为红黑树,当链表的长度<6时,红黑树会重新恢复成链表
-
package cn.tedu.review; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class TestMap { public static void main(String[] args) { //1.提示用户输入字符串并接收 System.out.println("请输入字符串"); String input = new Scanner(System.in).nextLine(); //2.要统计字符串中 字符的个数,存在映射关系 用map集合 //为什么要使用字符作为key? 因为map中的key不可以重复 //也就是说 字符不允许重复 但字符出现的次数可以重复 Mapmap = new HashMap<>(); System.out.println(map);//map中现在没有数据 需要存入 //3.准备向map中存入数据 //3.1遍历用户输入的字符串 拿到每个字符 for(int i= 0;i 进程 线程 进程 线程 Thread
概念:
进程就是正在运行的程序 , 给程序加入了时间概念, 是动态的,由CPU进行执行与计算。
特点:
- 独立性
- 动态性
- 并发性
什么是程序? 进程与程序的区别?
答: 程序:数据和指令的集合
区别: 进程动态的 程序静态的
多线程的特性
概念:
线程是 *** 作系统OS能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.
进程与线程关系
一个进程可以包含多个线程,也可以包含一个线程
只有一个线程的进程叫做单线程程序
每个线程在共享同一个进程中的内存的同时,又有自己独立的内存空间.
随机性
一个CPU【单核】只能执行一个进程中的一个线程。
因为CPU以纳秒级别甚至是更快的速度高效切换着,超过了人的反应速度,这使得各个进程从看起来是同时进行的,也就是说,宏观层面上,所有的进程看似
【同时运行】,但是微观层面上是串行的【同一时刻,一个CPU只能处理一件事】。
串行与并行
串行是指同一时刻一个CPU只能处理一件事,类似于单车道
并行是指同一时刻多个CPU可以处理多件事,类似于多车道
cpu分时调度
时间片,即CPU分配给各个线程的一个时间段,称作它的时间片,即该线程被允许运行的时间,如果在时间片用完时线程还在执行,那CPU将被剥夺并分配给另
一个线程,将当前线程挂起,如果线程在时间片用完之前阻塞或结束,则CPU当即进行切换,从而避免CPU资源浪费,当再次切换到之前挂起的线程,恢复现场,继
续执行。
注意:我们无法控制OS选择执行哪些线程,OS底层有自己规则,如:
FCFS(First Come First Service 先来先服务算法) : 先来的就先处理完在处理后来的
SJS(Short Job Service短服务算法) : 不管多会来的,只要需要的时间片比正在执行的进程剩余所需的时间片短就先执行
线程的状态
线程的三种基础状态及其转换,简称”三态模型” :
就绪(可运行)状态:线程已经准备好运行,只要获得CPU,就可立即执行
执行(运行)状态:线程已经获得CPU,其程序正在运行的状态
阻塞状态:正在运行的线程由于某些事件(I/O请求等)暂时无法执行的状态,即线程执行阻塞
就绪 → 执行:为就绪线程分配CPU即可变为执行状态"
执行 → 就绪:正在执行的线程由于时间片用完被剥夺CPU暂停执行,就变为就绪状态
执行 → 阻塞:由于发生某事件,使正在执行的线程受阻,无法执行,则由执行变为阻塞
(例如线程正在访问临界资源,而资源正在被其他线程访问)
反之,如果获得了之前需要的资源,则由阻塞变为就绪状态,等待分配CPU再次执行
线程状态与代码对照
我们可以再添加两种状态:
创建状态:线程的创建比较复杂,需要先申请PCB,然后为该线程运行分配必须的资源,并将该线程转为就绪状态插入到就绪队列中
- 终止状态:等待OS进行善后处理,最后将PCB清零,并将PCB返回给系统
线程生命周期,主要有五种状态:
多线程代码创建方式1:继承Thread
新建状态(New) : 当线程对象创建后就进入了新建状态.如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法,线程即为进入就绪状态.
处于就绪(可运行)状态的线程,只是说明线程已经做好准备,随时等待CPU调度执行,并不是执行了t.start()此线程立即就会执行
运行状态(Running):当CPU调度了处于就绪状态的线程时,此线程才是真正的执行,即进入到运行状态
就绪状态是进入运行状态的唯一入口,也就是线程想要进入运行状态状态执行,先得处于就绪状态
阻塞状态(Blocked):处于运状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态才有机会被CPU选中再次执
行.
根据阻塞状态产生的原因不同,阻塞状态又可以细分成三种:
等待阻塞:运行状态中的线程执行wait()方法,本线程进入到等待阻塞状态
同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态
其他阻塞:调用线程的sleep()或者join()或发出了I/O请求时,线程会进入到阻塞状态.当sleep()状态超时.join()等待线程终止或者超时或者I/O处理完毕时线程重新转入就绪状态
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
步骤:
- 定义自己的多线程类TicketThread,并且继承Thread
- 重写父类的run(),里面是我们自己的业务
- 创建多个自定义线程类对象
- 通过线程对象.start()将线程加入到就绪队列中
- 查看多线程抢占资源的效果
构造方法摘要:
多线程代码创建方式2:实现Runnable
- Thread() 创建一个新的线程对象,名字是系统自定义的
- Thread(String name) 与上面功能一致,还可以自定义线程名
- 可以通过调用父类Thread的含参构造Thread(String name)
- 给自定义线程对象起名字,调用方式:super(name);
定义自己的业务类,并且实现接口Runnable
在业务类中添加接口里的抽象方法run(),并实现业务
创建唯一的业务类对象
创建多个Thread类的对象,作为多个线程对象
并将刚刚的业务对象传入
使用多个线程类对象调用start(),将线程加入到就绪队列之中
查看多线程抢占资源的效果
构造方法摘要
- Thread(Runnable target) 创建一个线程对象,参数为Runnable实现类的对象
- Thread(Runnable target, String name) 与上面功能一致,还可以自定义线程名
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)