线程安全问题

问题:模拟窗口售票,总票数50张,两个窗口售票,运行结果出现同号票。比如下面代码:

在这里插入图片描述

原因:两个线程执行的代码片段是同一段,对同一个ticket进行计算,t1线程对ticket计算还没有全部执行完,另一个线程参与进来执行,导致错误的数据产生。
解决方式:
对ticket变量的计算由始至终都是一个线程来操作,即使在执行过程中,其他线程由执行权,也不能参与对ticket的计算
前提:
1.两个或两个以上的线程
2.保证多线程间看到的是同一个锁对象
锁对象:可以是任意对象,没有限制。
多线程对共享资源的所有操作放在同步中。

1.同步代码块:
syncronized(锁对象){

}

当t1线程有执行权,执行到同步块语句时,首先判断锁的状态,如果是关则不能进入同步中;如果是开,立即获取锁对象,并且把锁对象由开改为关,进入同步中执行代码。当同步块中的代码执行完,出了同步块,会立即释放锁,并将锁由关改为开。即使t1在同步块中时,t2获取到了执行权,那么它也不能进入同步中。

在上述代码中添加同步代码块例如:
在这里插入图片描述
好处:结局了安全问题。
弊端:每次执行都需判断锁,降低了效率
如果有同步还有安全问题:
1.是否是同一个锁对象
2。不可分割的代码是否都在同步中

2.同步方法
修饰符 synchronized 返回值类型 方法名(参数){
}
定义的方法使用了同步关键字进行了修饰,那么这个方法就有了同步的特性,具有锁。
实例方法:this

在这里插入图片描述
静态方法: 类名.class

在这里插入图片描述

3.显示锁—jdk5.0
是个Lock接口,接口中封装了lock和unlock方法,用于获取锁和释放锁。
实现类:ReentrantLock

在这里插入图片描述

死锁:
多线程启动执行时,各自持有各自的资源,想要对方的资源,对方又不释放,最终导致程序不能继续向下执行,程序又不能停止,出现了一种焦灼的状态,卡了的现象。
注意:实际开发中千万不能出现死锁。

例子:锁的嵌套,即同步嵌套,可能会出现死锁:

在这里插入图片描述

在这里插入图片描述
建议在开发中不要使用锁的嵌套,因为可能出现死锁。

测试:
jstack pid值
查看pid值:cmd然后输入 tasklist命令查看java或javaw的pid在进行测试

ThreadLocal:
我们创建的变量是能被各个线程访问的,而ThreadLocal类可以让每个线程都有自己的专属本地变量,每个线程都有该变量的本地副本,避免线程安全问题。ThreadLocal 可以理解为只是ThreadLocalMap的封装,传递了变量值。每个Thread中都具备一个ThreadLocalMap,而ThreadLocalMap可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对。
ThreadLocal中存在内存泄漏问题,ThreadLocalMap中使用的key为ThreadLocal的弱引用,而value则是强引用,如此以来在ThreadLocal在未被外部强引用的情况下,垃圾回收处理的时候,会回收key,而value不会被清理掉,这样一来ThreadLocalMap中就会出现key为null的Entry,value永远不会被GC回收,会出现内存泄露问题,使用完ThreaLocal后调用remove方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值