Java笔记——Java并发

进程和线程的区别

进程是操作系统分配资源(进程id、虚拟内存,文件、socket资源等等)的最小单元;

线程是操作系统进行任务调度的最小单元,线程隶属于进程。

1,Java如何开启线程?怎么保证线程安全?

开启线程的方法:

1)继承Thread类,实现run方法,调用start方法;

2)实现Runnable接口,实现run方法,通过Thread类或者线程池类启动;

3)实现Callable接口,实现call方法,通过FeatureTask创建线程,可以获取执行结果;

4)通过线程池启动线程。

保证线程安全的方法:

加锁,保证线程的可见性,串行修改共享资源

1)使用JVM提供的锁,即使用synchronized关键字;

2)使用JDK提供的锁,实现了Lock接口的锁,可重入锁,读写锁等。

2,synchronized

Java中每一个对象都是锁,synchronized使用的锁保存在对象头的Mark Word中

synchronized使用有三种形式:

1)修饰普通成员方法,锁是当前实例对象;

2)修饰静态成员方法,锁是当前类的class对象;

3)synchronized代码块,锁是括号中指定的对象。

使用sychronized,加锁和解锁是自动完成的;退出同步方法块,或者同步方法块内抛出异常,会自动释放锁。

在早期(JSE1.6之前的版本)synchronized采用操作系统内核API实现加锁和解锁,性能开销比较高,被称为重量级锁;JSE1.6之后对synchronized进行极大的优化,引入偏向锁、轻量级锁,加锁和解锁性能损耗得到很大的改善。随着锁竞争程度的增加,synchronized使用的锁会从偏向锁升级到轻量级锁,进而升级到重量级锁,锁升级之后不能降级。

Java对象头

32位JVM,1个字是32位;64位虚拟机,1个字是64位。

数组对象,占用3个字宽;

非数组对象,占用2个字宽。

对象头的结构

长度

内容

说明

1个字宽

Mark Word

存hashCode或锁信息等

1个字宽

Class Metadata Address

存对象类型数据的指针

1个字宽

Array Length

如果是数组对象,存数组的长度

对象头Mark Word的结构

锁状态

4bit

1bit 是否是偏向锁

2bit 锁标志位

无锁状态

分代年龄

0

01

偏向锁

线程ID+epoch

分代年龄

1

01

轻量级锁

指向栈中锁记录的指针

00

重量级锁

指向互斥量(重量级锁)的指针

10

GC标记

11

对象头里锁的状态不同,对象头Mark Word里各个位存的信息也不同。

偏向锁

大多数情况下,锁不仅不存在竞争,而且总是被同一个线程获得。

在没有竞争的情况下,synchronized使用偏向锁。

轻量级锁

在竞争比较小的时候,synchronized的锁会升级到轻量级锁。

轻量级锁在获取锁不成功的时候,线程不会阻塞,而是自旋,通过CAS操作尝试获取锁。自旋会消耗CPU,当一定次数的自旋还是获取不到锁时,synchronized会将锁升级为重量级锁,线程获取锁不成功时会阻塞等待,同时让出CPU。

synchronized锁的优缺点

优点

缺点

使用场景

偏向锁

加锁和解锁不需要额外的开销,纳秒级可以忽略不计

存在竞争时会发生锁撤销带来开销

只有一个线程访问同步块(单例模式初始化实例)

轻量级锁

竞争的线程不会阻塞,提高了响应速度

如果始终得不到锁,自旋会消耗CPU

追求响应时间

同步块执行非常快

重量级锁

竞争的线程阻塞不自旋,不消耗CPU

线程阻塞,响应速度慢

追求吞吐量

同步块执行比较长

Java对象内存布局

使用openjdk的jol-core工具包

<!--maven依赖,注意其他版本输出信息有差异-->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>

场景一

第一次输出是无锁状态;第二次输出是轻量级锁状态。

场景二

 

第一次输出是无锁状态;第二次o2并没有加锁,输出偏向锁状态,但是Mark Word没有记录持有锁的线程id;第三次o2加锁后,输出偏向锁状态,Mark Word有记录持有锁的线程id。第四次同步代码块执行完之后o2上的锁应该已经释放,但是仍然输出的是偏向锁状态,Mark Word也记录着线程id,并没有撤销锁,注意当存在其他线程竞争时才会撤销偏向锁,如果竞争激烈会升级到轻量级锁或者重量级锁。

关于第二次输出结果的说明,JVM的一个特性

synchronized不响应中断异常

synchronized获取锁时,如果没有竞争到锁线程阻塞后,不会响应中断异常。

JDK中实现Lock接口的锁,使用lockInterruptibly方法能够响应中断异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值