019_多线程同步

2019-12-17

多线程安全问题

当多个线程共同访问一个对象时,造成数据不一致!效果图示:

A线程将"Hello"存入数组的第一个空位;B线程将"World"存入数组的第一个空位,会造成值的覆盖,导致数据不一致。

原因总结:

  1. 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。

  2. 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。

  3. 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。

场景安全问题演示

推延到应用程序中,是如何产生安全问题的,举例:一对夫妇共同操作同一账户,执行取钱操作。

 

由于验证代码if(money<balance) 和 balance -= money 这两个是一个整体(原子操作),而多线程会破坏这种原子操作导致了安全问题! 

 

解决方案

同步代码块
synchronized(临界资源对象){ //对临界资源对象加锁
    //代码(原子操作)
}
注: "每个对象都有一个互斥锁标记,用来分配给线程的。“
    "只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块。"
    "线程退出同步代码块时,会释放相应的互斥锁标记。"

同步方法

synchronized 返回值类型 方法名称(形参列表){ //对当前对象(this)加锁
     //代码(原子操作)
}
注:
   "只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块。"
    "线程退出同步代码块时,会释放相应的互斥锁标记。"

死锁

死锁:

  • 当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁。

  • 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已拥有的锁标记,由此可能造成死锁。

演示案例: 一绑匪绑了张三的女友,给张三打电话要求张三先交钱,再放其女友;张三说只有先放人再给钱。用程序模拟:

 

创建执行绑匪任务的线程,手握两把锁

创建执行男友任务的线程,也是手握俩两把锁,顺序相反!

双方互相持有对方所需的锁标记而不相让,这样僵持的状态称之为死锁

生产者和消费者问题:

  • 若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了能使生产者和消费者能并发执行,在两者之间设置一个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区,消费者从缓冲区中取走产品去消费,显然生产者和消费者必须同步,即不允许消费者去一个空的缓冲区取产品,也不允许生产者到一个满的缓冲区放入产品。

通过死锁和生产者消费者两个问题发现,在引入了锁机制后带来了一些问题,因此设想如果线程之间能通信该多好啊!

线程通讯

要解决以上的问题,必须要在线程间通信。

再通过代码演示(用两个线程,用wait和notify方法,体现等待和通知的思想即可)

再在此案例的基础上,构建多个线程,使用notify All再演示一下

wait() 主动释放锁,进入无限期等待

notify All()通知唤醒因obj对象而无限等待的线程

 

完善整个线程状态图