Java多线程学习总结(三)

Java多线程学习总结(三)

——2020.02.23学习总结

线程同步(二)

(1)同步阻塞

昨天的学习知道了,线程可以通过调用synchronized方法来获得锁;还有一种机制可以获得锁,即通过进入一个同步阻塞。当线程进入如下形式的阻塞:

	synchronized (obj){
	   //代码
    }

于是它会获得obj的锁,这会获得一个Java对象锁。

(2)监视器概念

一种设计模式,可以在不需要程序员考虑如何加锁的情况下,保证多线程的安全性。监视器的特性有:

  • 监视器是只包含私有域的类
  • 每个监视器类的对象有一个相关的锁
  • 使用该锁对所有的方法进行加锁
  • 该锁可以有任意多个相关条件

如果一个方法用synchronized关键字声明,那么它表现的就像是一个监视器方法。

(3)Volatile域

volatile为实例域的同步访问提供了一种免锁机制,如果一个域为volatile,那么编译器和虚拟机就知道该域可能被另一个线程并发更新的。
假设对共享变量除了赋值之外并不完成其他操作,那么可以将这些共享变量声明为volatile。
笔试常考:volatile保证了变量的可见性(visibility),被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象。但它不能保证原子性。

(4)final变量

当一个域被声明为final是,多个线程可以安全地访问一个共享域。

(5)原子性

java.util.concurrent.atomic包中有很多类来保证操作的原子性。

(6)死锁

死锁产生的原因:

  • 因竞争资源发生死锁 现象:系统中供多个进程共享的资源的数目不足以满足全部进程的需要时,就会引起对诸资源的竞争而发生死锁现象
    (1)可剥夺资源和不可剥夺资源:可剥夺资源是指某进程在获得该类资源时,该资源同样可以被其他进程或系统剥夺,不可剥夺资源是指当系统把该类资源分配给某个进程时,不能强制收回,只能在该进程使用完成后自动释放
    (2)竞争不可剥夺资源:系统中不可剥夺资源的数目不足以满足诸进程运行的要求,则发生在运行进程中,不同的进程因争夺这些资源陷入僵局。
    举例说明: 资源A,B; 进程C,D
    资源A,B都是不可剥夺资源:一个进程申请了之后,不能强制收回,只能进程结束之后自动释放。内存就是可剥夺资源
    进程C申请了资源A,进程D申请了资源B。
    接下来C的操作用到资源B,D的资源用到资源A。但是C,D都得不到接下来的资源,那么就引发了死锁。
    (3)竞争临时资源
  • 进程推进顺序不当发生死锁

产生死锁的四个必要条件:

  • (1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
  • (2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
  • (3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
  • (4)环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链

处理死锁的基本方法:

  • 预防死锁:通过设置一些限制条件,去破坏产生死锁的必要条件
  • 避免死锁:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁
  • 检测死锁:允许死锁的发生,但是通过系统的检测之后,采取一些措施,将死锁清除掉
  • 解除死锁:该方法与检测死锁配合使用
(6)线程局部变量

线程间共享变量是有风险的,有时候要避免共享变量,使用ThreadLocal类为各个线程提供各自的实例。

(7)读/写锁

ReentrantReadWriteLock类。如果很多线程从一个数据结构读取数据而很少线程修改其中数据的话使用。允许对读线程共享访问,对写线程互斥访问。使用读写锁的步骤:

  • 构造一个ReentrantReadWriteLock对象:
private ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
  • 抽取读锁和写锁
private Lock readLock = rwl.readLock();//读锁
private Lock writeLock = rwl.writeLock();//写锁
  • 对所有的获取方法加读锁
	public int getMethod(){
        readLock.lock();
        try {
            //...
        }finally {
            readLock.unlock();
        }
       
    }
  • 对所有的修改方法加写锁
	public void setMethod(){
        writeLock.lock();
        try {
            //...
        }finally {
            writeLock.unlock();
        }
    }

好了,当目前为止,多线程并发的知识的基础就已经全部有了印象,明天就继续学习更高一层次的内容了。

发布了31 篇原创文章 · 获赞 78 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43395911/article/details/104455413
今日推荐