线程控制方法
  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器 按照线程的优先级决定应调度哪个线程来执行。
  • 线程的优先级用数字表示,范围从1到10
    • Thread.MIN_PRIORITY = 1
    • Thread.MAX_PRIORITY = 10
    • Thread.NORM_PRIORITY = 5
  • 使用下述方法获得或设置线程对象的优先级。
    • int getPriority();
    • void setPriority(int newPriority);

注意:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调用 优先级低的线程。

  • join ():阻塞指定线程等到另一个线程完成以后再继续执行
  • sleep ():使线程停止运行一段时间,将处于阻塞状态,如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行!
  • yield ():让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态.如果调用了yield方法之后,没有其他等待执行的线程,这个时候当前线程就会马上恢复执行!
  • setDaemon()
    • 可以将指定的线程设置成后台线程
    • 创建后台线程的线程结束时,后台线程也随之消亡
    • 只能在线程启动之前把它设为后台线程
  • interrupt():并没有直接中断线程,而是需要被中断线程自己处理
  • stop():结束线程,不推荐使用
线程同步实战
  • 应用场景:多个用户同时操作一个银行账户。每次取款100元,取款前先检查余额是否足够。如果不够, 放弃取款

  • 分析

    • 使用多线程解决
    • 开发一个取款线程类,每个用户对应一个线程对象
    • 因为多个线程共享同一个银行账户,使用Runnable方式解决
  • 思路

    • 创建银行账户类Account
    • 创建取款线程AccountRunnable
    • 创建测试类TestAccount,让两个用户同时取款
  • 当多个线程访问同一个数据时,容易出现线程安全问题。需要让线程同步,保证数据安全

  • 当两个或两个以上线程访问同一资源时,需要某种方式来确保资源在某一时刻只被一个线程使用

线程同步的实现方案
  • 同步代码块
    • synchronized (obj){ }
  • 同步方法
    • private synchronized void makeWithdrawal(int amt) {}
同步监视器
  • synchronized (obj){ }中的obj称为同步监视器
  • 同步代码块中同步监视器可以是任何对象,但是推荐使用共享资源作为同步监视器
  • 同步方法中无需指定同步监视器,因为同步方法的同步监视器是this,也就是该对象本事
同步监视器的执行过程
  • 第一个线程访问,锁定同步监视器,执行其中代码
  • 第二个线程访问,发现同步监视器被锁定,无法访问
  • 第一个线程访问完毕,解锁同步监视器
  • 第二个线程访问,发现同步监视器未锁,锁定并访问
Lock锁
  • JDK1.5后新增功能,与采用synchronized相比,lock可提供多种锁方案,更灵活
  • java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语 言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁 定语义。
  • ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义, 但是添加了类似锁投票、 定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。
  • 注意:如果同步代码有异常,要将unlock()写入finally语句块
Lock和synchronized的区别
  • Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
    优先使用顺序:
  • Lock----同步代码块(已经进入了方法体,分配了相应资源)----同步方法(在方法体之外)
线程同步的好处

解决了线程安全问题

线程同步的缺点
  • 性能下降
  • 会带来死锁
死锁
  • 当两个线程相互等待对方释放“锁”时就会发生死锁
  • 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
  • 多线程编程时应该注意避免死锁的发生