zoukankan      html  css  js  c++  java
  • JAVA多线程(五):线程同步(一)线程的同步

    1 问题的提出

    多个线程执行的不确定性引起执行结果的不稳定
    多个线程对账本的共享,会造成操作的不完整性,会破坏数据。

    2  模拟火车站售票程序,开启三个窗口售票

     

     

    1. 多线程出现了安全问题
    2. 问题的原因:
    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
    3. 解决办法:
    对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。 

    3 Synchronized的使用方法

    Java对于多线程的安全问题提供了专业的解决方式:同步机制
    1. 同步代码块:
      synchronized (对象){
        // 需要被同步的代码;
      }
    2. synchronized还可以放在方法声明中,表示整个方法为同步方法。
      例如:
      public synchronized void show (String name){
        ….
      }
     
    3.1 分析同步原理

    3.2 同步机制中的锁 

    同步锁机制:
      在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁之时,另一个任务就可以锁定并使用它了。
    synchronized的锁是什么?
      任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)。
      同步方法的锁:静态方法(类名.class)、非静态方法(this)
      同步代码块:自己指定,很多时候也是指定为this或类名.class
    注意:
      必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全
      一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方法共用同一把锁(this),同步代码块(指定需谨慎)

    3.3 同步的范围

    1、如何找问题,即代码是否存在线程安全?(非常重要)
      (1)明确哪些代码是多线程运行的代码
      (2)明确多个线程是否有共享数据
      (3)明确多线程运行代码中是否有多条语句操作共享数据
    2、如何解决呢?(非常重要)
      对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
      即所有操作共享数据的这些语句都要放在同步范围中
    3、切记:
      范围太小:没锁住所有有安全问题的代码
      范围太大:没发挥多线程的功能。

    3.4 释放锁的操作

    当前线程的同步方法、同步代码块执行结束。
    当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
    当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
    当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

    3.5 不会释放锁的操作

    线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
     
    线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。
      应尽量避免使用suspend()和resume()来控制线程

    3.6 单例设计模式之懒汉式(线程安全) 

    3.7 线程的死锁问题 

    死锁
      不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
      出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
    解决方法
      专门的算法、原则
      尽量减少同步资源的定义
      尽量避免嵌套同步

     4 Lock(锁) 

      从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
      java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
      ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

     5 synchronized 与 Lock 的对比

    1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放
    2. Lock只有代码块锁,synchronized有代码块锁和方法锁
    3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
    优先使用顺序:
    Lock --》同步代码块(已经进入了方法体,分配了相应资源)--》同步方法(在方法体之外)
     
  • 相关阅读:
    poj 1860 Currency Exchange(最短路径的应用)
    poj 2965 The Pilots Brothers' refrigerator
    zoj 1827 the game of 31 (有限制的博弈论)
    poj 3295 Tautology (构造法)
    poj 1753 Flip Game(枚举)
    poj 2109 (贪心)
    poj 1328(贪心)
    Qt 对单个控件美化
    Qt 4基础
    Bash Shell
  • 原文地址:https://www.cnblogs.com/qiu-hua/p/14231391.html
Copyright © 2011-2022 走看看