创建线程
在Java中,创建线程有3种方式
(1)继承Thread类,并且重写run方法
Thread类中的run方法不是抽象方法,Thread类也不是抽象类
MyThread当继承了Thread类之后,他就是一个独立的线程
要让线程启动,调用线程的start方法
当调用start方法启动一个线程时,会执行重写run方法的代码
调用的是start,执行的是run,为什么不直接调run?
start叫做启动线程,有特殊含义的方法
现成的优先级是概率问题,做不到百分百;90%先跑主方法。10%先跑MyThread
能用接口尽量不用继承
守护线程
java中提供两种类型的线程:
1、用户线程
2、守护程序线程
守护线程为用户线程提供服务,仅在用户线程运行时才需要
守护线程对于后台支持任务非常有用
垃圾回收,大多数JVM线程都是守护线程
创建守护线程
任何继承创建他的线程守护进程状态。由于主线程是用户
线程的生命周期**
NEW: 这个状态主要是线程未被start()调用执行
BUNNABLE:线程正在JVM中被执行,等待来自操作系统的调度
BLOCKED:堵塞,因为某些原因不能立即执行需要挂起等待
WAIITING:无限期等待。object类,如果没有唤醒,则一直等待
TIMED-WAIITING:有限期等待,线程等待一个指定的时间
TERMINATED:终止线程的状态,线程已经执行完毕
等待和阻塞两个概念有点像,阻塞因为外部原因,需要等待,而等待一般是主动调用方法,发起主动地等待。等待还可以传入参数确定等待时
1、cpu多核缓存结构
物理内存:硬盘内存(固态硬盘,尽量不要选择混合硬盘)
CPU缓存是为了提高程序运行的性能,现在cpu在很多方面对程序进行优化
cpu处理速度最快,内存次之,硬盘速度最低
在cpu处理内存数据时,如果内存运行速度太慢,就会拖累cpu的速度,为了解决这样的问题,cou设计了多级的缓存策略
cpu分为三级缓存,每个cpu都有L1,L2缓存,但是L3缓存是多核公用的
cpu查找数据时,cpu--》L1--》L2--》L3--》内存--》硬盘
进一步优化,cpu每次读取一个数据,读取的时候与他相邻的64个字节的数据;。
英特尔提出来一个MESI协议
1、修改态,此缓存被动过,内容与主内存中不同,为此缓存专有
2、专有态,此缓存与内存一致,但是其他cpu没有
3、共享态,此缓存与主内存一致,其他的缓存也有
4、无效态,此缓存无效,需要从主内存中重新读取
线程安全
【指令重排】(了解就行)
四条指令,四个人在四张纸上写下【恭喜发财】。
java内存模型-JMM:
尽量做到硬件和操作系统之间到达一致的访问效果。
使用volatile关键字来保证一个变量在一次读写操作时,避免指令重排,
我们在读写操作之前加入一条指令,当cpu碰到这条指令后必须等到前面的执行执行完成才能继续执行下一个
线程安全的可见性
thread线程一直在高速读取缓存中的isOver,不能感知主线程已经
线程争抢
解决线程争抢的问题最好的办法就是【加锁】
synchronized同步锁,线程同步
线程安全的实现方法
(1)数据不可变
一切不可变的对象一定是线程安全的
对象的方法的实现方法的调用者,不需要再进行任何的线程安全的保障措施。
比如final关键字修饰的基本数据类型,字符串
只要一个不可变的对象被正确的创建出来,那外部的可见状态,永远不会改变
(2)互斥同步 加锁 【悲观锁】
(3)非阻塞同步【无锁编程】,自旋,我们会用cas来实现这种非阻塞同步
(4)无同步方案,多个线程需要共享数据,但是这些数据又可以在单独的线程中计算,得出结论
我们可以把共享数据的可见范围限制在一个线程之内,这样就无需同步。把共享的数据拿过来。我用我的,你用你的,从而保证线程的安全 threadLocal
优先级决定不了运行顺序