【并发编程】2.锁与等待通知机制

互斥锁

【并发编程理论】1.并发问题的由来
中说明了原子性为 CPU在执行一个或多个操作的过程中不被中断。
然而在多核CPU的情况下,有一些情况即使操作不被中断,也会引发线程安全问题。

互斥性则为同一时刻只有一个线程执行,无论多核或者单核的情况都可以满足原子性。

一、锁的设计思想

  • 1.把需要互斥执行的代码成为临界区
  • 2.线程在执行临界区代码时需要获取锁(同时只有一个线程可以获取锁,已被占用就要等待),并且加锁称为 Lock
  • 3.执行完临界区代码后释放锁,称为UnLock

锁与临界区代码最好存在关联,这样可以使用最小粒度的锁来保护需要互斥

二、Synchronized关键字

是Java中锁的一种实现,可以用于修饰代码块,也可以用于修饰方法。

	//加锁的是调用该方法的对象 this
	public synchronized void  method(){
    }
	//加锁的是 该类的 .class
    public static synchronized  void method2(){
    }
	//加锁的是指定的对象 obj
    public   void method3(){
        synchronized(obj){
        }
    }

synchronized 存在的问题申请资源的时候,如果申请不到,线程直接进入阻塞状态,而线程进入阻塞状态,啥都干不了,也释放不了线程已经占有的资源


三、Lock

Lock是JavaSDK提供的另一种实现互斥锁的方式,并且解决了synchronized关键字的资源不可抢占问题

解决思路

  • 1.超时机制 指定时间内获取不到锁,不进入阻塞状态
  • 2.能够响应中断 给阻塞的线程发送中断信号的时候,能够唤醒它
  • 3.非阻塞的获取锁 当尝试获取锁失败,并不进入阻塞状态,而是直接返回

对应Lock中的方法

// 支持中断的 API
void lockInterruptibly()
        throws InterruptedException;
// 支持超时的 API
boolean tryLock(long time, TimeUnit unit)
        throws InterruptedException;
// 支持非阻塞获取锁的 API
boolean tryLock();

锁的使用范式

class X {
        private final Lock rtl = new ReentrantLock();
        int value;
        public void addOne() {
            // 获取锁
            rtl.lock();
            try {
                value+=1;
            } finally {
                // 保证锁能释放
                rtl.unlock();
            }
        }
    }

四、死锁问题

死锁问题本质是: 一组互相竞争资源 的线程因互相等待,导致“永久”阻塞的现象

问题场景
假设线程 T1 执行账户 A 转账户 B 的操作,账户 A.transfer(账户 B);
线程 T2 执行账户 B 转账户 A 的操作,账户 B.transfer(账户 A)。

此时程序就进入死锁,线程之间互相等待。

要避免死锁就需要分析死锁发生的条件,只有以下这四个条件都发生时才会出现死锁:

  1. 互斥,共享资源 X 和 Y 只能被一个线程占用;

  2. 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
    解决办法: 同时申请所有资源

  3. 不可抢占,其他线程不能强行抢占线程 T1 占有的资源;
    解决办法: 使用Lock API

  4. 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。
    解决办法: 对需要的资源进行排序 例如:全都按照从小到大的顺序


五、线程间的通信:等待与通知机制

当线程抢占锁的资源时,如果抢占不到就一直循环抢占,会非常的浪费资源。

使用等待通知机制可以进行优化,在获取不到锁时等待,占用锁线程释放锁时通知所有等待的线程抢占锁。
当不满足条件进入等待队列
当锁被释放,等待队列中的线程去抢占锁

java中提供的API是
wait()、notify()、notifyAll()

这些方法操作的都是互斥锁的对应的等待队列
调用这些方法的对象应该是加锁的对象

posted @ 2020-07-13 16:17  ShinyRou  阅读(261)  评论(0编辑  收藏  举报