java--线程(二)(线程安全问题)

一、线程安全问题

  问题描述:现在有A、B两个线程,同时往数组中存储数据,A线程存储“Hello”,B线程存储“World”

  线程运行:假设A线程先抢到时间片,查找到下标为0 的位置没有数据,时间片到期,这时候下标为0的位置没有数据,然后B线程抢到时间片,查找到下标为0的位置没有数据,同时把“World”放到下标为0 的这个位置,之后A线程抢到时间片,继续执行之前的操作,把“Hello”放到下标为0的位置。这就造成了线程不安全。

       

 

 

    线程不安全:

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

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

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

二、线程的同步

  同步代码块:

    synchronized(临界资源对象){//对临界资源对象加锁

    //代码 (原子操作)

    }

  注:每一个对象都有一个互斥锁标记,用来分配给线程的。

    只拥有对象互斥锁标记的线程,才能进入该对象加锁的同步代码块

    线程退出同步代码块时,会释放相应的互斥锁标记

  线程状态:

  同步方法:

    synchronized 返回值类型 方法名称(形参列表){//对当前对象(this)加锁

       //代码 (原子操作)

    }

 

 

    注:只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步方法中

      线程退出同步方法时,会释放相应的互斥锁标记

  同步规则:

     只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记

     如调用不包含同步代码块的方法,或普通方法时,则不需要锁标记,可直接调用

三、经典问题

  死锁:

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

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

四、线程通信

  等待:

    public final void wait()

    public final void wait(long timeout)

    必须在对obj加锁的同步代码块中。在一个线程中,调用obj.wait()时,此线程会释放其拥有的所有锁标记。

              同时此线程阻塞在o的等待队列中。释放锁,进入等待队列。

  通知:

    public final void notify()

    public final void notifyAll()

    必须在对obj加锁的同步代码块中。从obj的waiting中释放一个或全部线程。对自身没有任何影响

posted @ 2021-01-18 16:55  改Bug的小魔女  阅读(80)  评论(0编辑  收藏  举报