(更新中)谈谈个人对java并发编程中(管程模型,死锁,线程生命周期等问题) 见解

之前未曾接触过多线程编程  公司的项目开始用到多线程,所以自己谈谈个人对于并发编程的见解。

并发编程会导致线程不安全,常说的线程不安全指的是  多个线程操作一个共享数据,导致线程之间的读取到的数据不一致。

并发编程导致线程不安全的根源   可见性  原子性    有序性

 1 .可见性     cpu缓存导致。 一般cpu缓存中进行操作之后再将数据写到内存,在多核服务器中  每个线程都会分配一个cpu  都会在各自的cpu中进行处理再将数据统一写到内存中。每个cpu缓存中的数据对于其他的线程,都是不可见的。导致最后写入内存,然后再从内存中读出来时候数据不一致。

 2 原子性      线程切换导致,在java语句中一行语句在计算机底层进行了多次操作。比如创建一个对象,new   在在堆中开辟一块空间  最后将地址赋予这个对象  如果在期间发生那个线程的切换  就可能会报错

3有序性       编译优化产生。指的是  在代码在JVM上执行的时候都会进行一定的编译优化,在优化之后  可能在创建对象的时候  先是将地址指向了对象然后再分配的内存空间

要解决这些问题,理论上禁用缓存和编译优化就可以了,对于可见性  使用volidate 关键字和 happen-before 规则就可以避免了。原子性全部用synchornized,禁用编译优化,似乎了就解决。但是显然不现实,我们需要考虑到性能。(细粒度锁有时间再补充)

大家也许都知道,实际上所有的并发问题都可以用信号量来解决。这个信号量实际上和管程是一样的 ,都能用来处理并发问题。

管程是一种模型,是一把解决并发的万能钥匙,Java中的synchronized时间上就是采用了管程的思想。配合 wait() notify().notifyAll().

在synchronized下面会自动的加上  lock    unlock的操作,必须要注意的是  加锁的资源一定要不变。对象是this,整个类为字节码对象。

比如 a转账给b 两个对象的账户都要被锁定。怎么办?

这个时候先锁定  a   然后再锁定b.如果在a转给 b,a账户被锁定,等待锁定b账户,b此刻也要转给a,b锁定等待锁定a.此刻,就出现了一组资源相互等待各自所需资源,而出现的一组永久循环等待的现象。

这就是死锁!

一般发生死锁没有什么好的办法  一般只有重启服务器。所以只能去避免死锁的发生。

首先要搞清楚  发生死锁的必要条件

1  互斥

2 占用且等待

3 不可抢占

4 循环等待 

 理论上只要打破其中的一个条件就能避免死锁,但是  我们 用锁就是希望互斥,所以这个没办法去处理  不可抢占的特性可以使用第三方的sdk来解决。

现在讲一下占用且等待。实际上 ,我们不要一个一个去锁定,而是等到拿到两个账户了一起锁定。比如我们可以创建一个单例的工具类去获取这两个对象,如果只拿到其中的一个的话都不会锁定。

对于循环等待的话  我们可以定一个一定的规则来进行排序 如果需要一组细粒度锁 会将两个锁进行排序 从小到大的顺序进行加锁 这样也能避免这个循环等待的问题

总之,在使用细粒度锁一定要注意死锁的问题。

 其实不只是死锁,也会有活锁和饥饿两种情况也会导致线程执行不下去的情况。

活锁指的是当

猜你喜欢

转载自www.cnblogs.com/mrxiab/p/10676116.html