oo

java线程

2018-09-27  本文已影响5人  溜溜猪66


1.实现线程3中方式:

1.1内核线程->轻量级进程: 传统意义上的线程,由内核线程实现的高级接口,进行创建和其他操作的时候需要进行系统调用,频繁的在内核态和用户态进行切换,成本较高 1:1

1.2用户线程:在用户态中实现,不需要进行系统调用,效率高,实现复杂(阻塞、中断),弃用 1:N

1.3混合实现:在用户态中实现,但是通过轻量级线程进行必要的系统调用 M:N

2.JAVA线程:基于操作系统原生模型:windows linux 线程和轻量级进程都是1:1

3.JAVA线程调度:协同式、抢占式

4.协同式:线程的执行由自己决定,执行完成主动通知操作系统切换到下一个线程,无同步问题,但执行时间不可控制,很容易阻塞崩溃

5.抢占式:由操作系统调度,线程只能由操作系统分配执行时间(可以让出执行时间 yield),通过设置优先级可以多分配执行时间,但是因为JAVA线程依赖操作系统线程,所以优先级(JAVA优先级并不一定和操作系统对应)不靠谱

6.java线程状态:


互斥同步

7.synchronized:使用monitorenter 和 monitorexit指令实现,执行enter时,锁计数器+1 执行exit -1 锁计数器为0 则释放锁,因为java线程是映射到操作系统的线程,所以阻塞和唤醒,都会有用户态到内核态的切换,所以比较耗时.jdk1.6之后 和reentrantlock性能差不多

8.ReentrantLock:比sychronized多了等待可中断:等待时间过长可以放弃等待、可实现公平锁:按照等待顺序获得锁synchronized不保证、锁可以绑定多个条件:可以绑定多个condition


非阻塞同步

9.通过操作和检测冲突的原子性,实现同步。但是存在ABA问题,因为检测冲突的时候检测的是地址,如果1个对象被回收之后的地址被分配给另外一个对象,会被判断为是同一个对象

10.可以使用theadlocal保存线程变量

11.自旋锁:线程的阻塞和唤醒都需要切换到内核态进行,带来了很大的开销,在很多时候对象锁定只会持续一小会,所以没有必要让线程阻塞,所以采用让线程执行一定数量的循环,用来等待锁释放。一定时间并不确定,而取决于上一次自旋的结果,如果上一次长时间没有获得锁,则会省略自旋过程

12.锁消除:如果没有对象和线程逃逸,则会消除锁

13.锁粗化:连续的对同一个对象加锁,则会优化把连续操作进行集体加锁

14.轻量级锁:对象头分为2部分,1.存储对象hashcode和对象gc年龄和锁标志位(未锁定:01 锁定 00),在32位和64位虚拟机中长度分别是32位和64位(Mark Word),2.存储指向方法区对象类型的指针,如果是数组还会存储长度

轻量级锁就是基于对象头第一部分,

线程进入同步块->在栈帧建立区域Lock Record->拷贝Mark Word ->用cas把对象头信息指向该区域->成功->把锁标志位修改为00

如果有多个线程争用同一个锁,那么会变成重量级锁,锁标志位变成10,所有不适合使用轻量级锁(多了cas操作)

15.偏向锁:在轻量锁的基础上,把CAS操作省略,偏向锁获取成功会把标志位设置为01,且把线程ID存储到对象头,如果有争用,终止偏向模式。

上一篇下一篇

猜你喜欢

热点阅读