• 请说出与线程同步以及线程调度相关的方法。


    wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理 InterruptedException 异常;

    notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且与优先级无关;

    notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

    提示:关于 Java 多线程和并发编程的问题,建议大家看我的另一篇文章《关于 Java并发编程的总结和思考》

    补充:Java 5 通过 Lock 接口提供了显式的锁机制(explicit lock),增强了灵活性以及对线程的协调。Lock 接口中定义了加锁(lock())和解锁(unlock())的方法,同时还提供了 newCondition()方法来产生用于线程之间通信的 Condition 对象;此外,Java 5 还提供了信号量机制(semaphore),信号量可以用来限制对某个共享资源进行访问的线程的数量。在对资源进行访问之前,线程必须得到信号量的许可(调用 Semaphore 对象的 acquire()方法);在完成对资源的访问后,

    线程必须向信号量归还许可(调用 Semaphore 对象的 release()方法)。

    下面的例子演示了 100 个线程同时向一个银行账户中存入 1 元钱,在没有使用同步机制和使用同步机制情况下的执行情况。

    银行账户类:

    /**

    * 银行账户

    * @author

    *

    */

    public class Account {

    private double balance;

    // 账户余额

    /**

    * 存款

    * @param money 存入金额

    */

    public void deposit(double money) {

    double newBalance = balance + money;

    try {

    Thread.sleep(10);

    // 模拟此业务需要一段处理时间

    }

    catch(InterruptedException ex) {

    ex.printStackTrace();

    }

    balance = newBalance;

    }

    /**

    * 获得账户余额

    */

    public double getBalance() {

    return balance;

    }

    }

    存钱线程类:

    /**

    * 存钱线程

    * @author

    *

    */

    public class AddMoneyThread implements Runnable {

    private Account account;

    // 存入账户

    private double money;

    // 存入金额

    public AddMoneyThread(Account account, double money) {

    this.account = account;

    this.money = money;

    }

    @Override

    public void run() {

    account.deposit(money);

    }

    }

    测试类:

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    public class Test01 {

    public static void main(String[] args) {

    Account account = new Account();

    ExecutorService service = Executors.newFixedThreadPool(100);

    for(int i = 1; i <= 100; i++) {

    service.execute(new AddMoneyThread(account, 1));

    }

    service.shutdown();

    while(!service.isTerminated()) {}

    System.out.println("账户余额: " + account.getBalance());

    }

    }

    在没有同步的情况下,执行结果通常是显示账户余额在 10 元以下,出现这种状况的原因是,当一个线程 A 试图存入 1 元的时候,另外一个线程 B 也能够进入存款

    的方法中,线程 B 读取到的账户余额仍然是线程 A 存入 1 元钱之前的账户余额,因此也是在原来的余额 0 上面做了加 1 元的操作,同理线程 C 也会做类似的事情,

    所以最后 100 个线程执行结束时,本来期望账户余额为 100 元,但实际得到的通常在 10 元以下(很可能是 1 元哦)。解决这个问题的办法就是同步,当一个线程

    对银行账户存钱时,需要将此账户锁定,待其操作完成后才允许其他的线程进行操作,代码有如下几种调整方案:

    在银行账户的存款(deposit)方法上同步(synchronized)关键字

    /**

    * 银行账户

    * @author

    *

    */

    public class Account {

    private double balance;

    // 账户余额

    /**

    * 存款

    * @param money 存入金额

    */

    public synchronized void deposit(double money) {

    double newBalance = balance + money;

    try {

    Thread.sleep(10);

    // 模拟此业务需要一段处理时间

    }

    catch(InterruptedException ex) {

    ex.printStackTrace();

    }

    balance = newBalance;

    }

    /**

    * 获得账户余额

    */

    public double getBalance() {

    return balance;

    }

    }

    在线程调用存款方法时对银行账户进行同步

    /**

    * 存钱线程

    * @author 骆昊

    *

    */

    public class AddMoneyThread implements Runnable {

    private Account account;

    // 存入账户

    private double money;

    // 存入金额

    public AddMoneyThread(Account account, double money) {

    this.account = account;

    this.money = money;

    }

    @Override

    public void run() {

    synchronized (account) {

    account.deposit(money);

    }

    }

    }

    通过 Java 5 显示的锁机制,为每个银行账户创建一个锁对象,在存款操

    作进行加锁和解锁的操作

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

    /**

    * 银行账户

    *

    * @author 骆昊

    *

    */

    public class Account {

    private Lock accountLock = new ReentrantLock();

    private double balance; // 账户余额

    /**

    * 存款

    *

    * @param money

    *

    存入金额

    */

    public void deposit(double money) {

    accountLock.lock();

    try {

    double newBalance = balance + money;

    try {

    Thread.sleep(10); // 模拟此业务需要一段处理时间

    }

    catch (InterruptedException ex) {

    ex.printStackTrace();

    }

    balance = newBalance;

    }

    finally {

    accountLock.unlock();

    }

    }

    /**

    * 获得账户余额

    */public double getBalance() {

    return balance;

    }

    }

    按照上述三种方式对代码进行修改后,重写执行测试代码 Test01,将看到最终的账户余额为 100 元。当然也可以使用 Semaphore 或 CountdownLatch 来实现同步。

  • 相关阅读:
    [ES6] Objects create-shorthand && Destructuring
    [ES6] Spread Operator
    [ES6] Rest Parameter
    [ES6] Function Params
    [React] Extracting Private React Components
    [Javascript] Array methods in depth
    生物-大脑极限:大脑极限
    生物-永生计划:永生计划
    物理-纳米技术-纳米技术应用:纳米技术应用
    物理-纳米技术:纳米技术
  • 原文地址:https://www.cnblogs.com/programb/p/13021439.html
Copyright © 2020-2023  润新知