2022-08-02 第二组 刘禹彤 学习笔记
打卡22天
###学习内容
多线程
1.创建线程
- 在java中创建线程有三种方式(1)继承thread类,并且重写run方法
1.Thread类中的run方法不是 抽象方法,Thread类也不是抽象类
2.mythread当继承了 Thread类之后,他就是一个独立的线程
3. 要让线程启动,调用线程的start方法,当调用start方法启动一
个线程时会执行重写的run方法的代码
mythread mythread = new mythread(); //为什么不直接调run //mythread.run();普通的对象调方法 mythread.start();//线程
(2)实行Runnable接口
使用箭头函数(lambda表达式)
无返回值
(3)实现Callable接口
有返回值
callable-->FutureTask-->RunnableFuture-->Runnable->Thread
2.守护线程
- java中提供两种类型的线程:1.用户线程
2.守护程序线程
- 守护线程为用户线程提供服务,仅在用户线程运行时才需要
- 守护线程对于后台支持任务非常有用(垃圾回收),大多数java线程都是守护线程
创建守护线程:任何线程继承和创建他的线程守护进程状态,由于主线程是用户线程,因此,在
- main方法内启动的任何线程默认是守护线程
3.线程的生命周期
- NEW:这个状态主要是线程未被start()调用执行
- TERMINATED:终止线程的状态,线程已经执行完毕
- RUNNABLE:线程正在JVM中被执行,等待来自操作系统的调用
- BLOCKED:阻塞,因为某些原因,不能立即执行需要挂起等待
- WAITTING:无限期等待,需要依赖Object类,如果没有唤醒,则一直等待
- TIMED_WAITTING:有限期等待,线程等待一个指定的时间
阻塞是外部原因需要等待
等待一般是主动调用方法,发起主动的等待,等待还可以传入参数确定等待时间
4.CPU多核缓存结构
- cpu缓存为了提高程序运行的性能,现在cpu在很多方面对程序进行优化,在cpu处理内存数据时,如果内存运行速度太慢,就会拖累cpu速度,为了解决这样的问题,cpu设计了多级缓存策略
- cpu分为三级缓存,每个cpu都有L1,L2缓存,但是L3缓存是多级公用的
- cpu查找数据时,CPU->L1->L2->L3->内存->硬盘
- 从CPU到内存:60-80纳秒
从CPU到L3:15纳秒
从CPU到L2:3纳秒
从CPU到L1:1纳秒
寄存器:0.3纳秒
进一步优化,cpu每读取一个数据,会同时读取与它相邻的64个字节的数据
【缓存行】
- 【指令重排】
java内存模型:JMM
尽量做到硬件和操作系统之间达到一致的访问效果
使用volatile关键字来保证一个变量在一次读写操作时,避免指令重排。
我们在读写操作之前加入一条指令,当CPU碰到这条指令后必须等到前面的执行执行完成才能继续执行下一条指令。【内存屏障】
5.可见性
thread线程一直在高速读取缓存中的isOver,不能感知主线程已经把isOVer改成了true
这就是线程的可见性的问题。
怎么解决?
volatile能够强制改变变量的读写直接在内存中操作
6线性争抢
解决线程争抢的问题最好的办法就是【加锁】
synchronized同步锁,线程同步
当一个方法加上了synchronized修饰,这个方法就叫做同步方法。
7.线性安全的实现办法
(1)数据不可变。
一切不可变的对象一定是线程安全的。
对象的方法的实现方法的调用者,不需要再进行任何的线程安全的保障措施。
比如final关键字修饰的基本数据类型,字符串。
只要一个不可变的对象被正确的创建出来,那外部的可见状态永远都不会改变。
(2)互斥同步。加锁。【悲观锁】
(3)非阻塞同步。【无锁编程】,自旋。我们会用cas来实现这种非阻塞同步。
(4)无同步方案。多个线程需要共享数据,但是这些数据又可以在单独的线程中计算,得出结果
我们可以把共享数据的可见范围限制在一个线程之内,这样就无需同步。把共享的数据拿过来,
我用我的,你用你的,从而保证线程安全。ThreadLocal
###学习心得
今天开始学习了多线程,基本算是java中最难的部分,知识点很多,要理解的概念也比较繁琐,需要反复记忆笔记
###掌握情况:一般
###课上练习
package b; public class Ticket implements Runnable{ private static final Object lock = new Object(); private static Integer count = 100; String name; public Ticket(String name) { this.name = name; } @Override public void run() { while(Ticket.count > 0){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (Ticket.lock){ System.out.println(name + "出票一张,还剩:" + Ticket.count-- + "张!"); } } } public static void main(String[] args) { Thread one = new Thread(new Ticket("一号窗口")); Thread two = new Thread(new Ticket("二号窗口")); one.start(); two.start(); } }
###运行结果