synchronized 修饰的方法无法实现互斥的问题解决

模拟订票场景,总共10张票,但是有20个人想要购买,所以定义了一个订票管理类专门负责操作这10张票,当然,操作票的时候使用到了synchronized,另外定义了一个调用订票方法的线程类用于模拟想要买票的人,然后创建20个线程模拟20个人来订票。但是运行测试的结果却并没有成功模拟这10张票的售卖过程,原因和处理分析如下:

订票管理类

设置 10 张票出售。

package com.example.study;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 订票管理
 * 
 * @author 李关钦
 * @date 2017年6月7日
 */
public class TicketManager {

    public static int ticket = 10;// 默认总共 10 张票

    private static final Logger logger = LoggerFactory.getLogger(TicketManager.class);

    /**
     * 售票,先检查是否有票,有则对原票数减一
     * 
     * @return
     */
    public synchronized boolean buyTicket() {

        // 延迟 1 秒钟,模拟实际情况中的处理时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (ticket > 0) {
            logger.info("current thread name is [{}] , before is [{}] , after is [{}]", Thread.currentThread().getName(), ticket, --ticket);
            return true;
        } else {
            logger.info("current thread name is [{}] , ticket is [{}] , The ticket has been sold out !!!", Thread.currentThread().getName(), ticket);
            return false;
        }

    }

}

订票线程

模拟订票的人。

package com.example.study;


/**
 * 订票线程,实现 Runnable 接口
 * 
 * @author 李关钦
 * @date 2017年6月7日
 */
public class BuyTicketRunnable implements Runnable {

    private TicketManager ticketManager = new TicketManager();

    @Override
    public void run() {

        ticketManager.buyTicket();

    }

}

测试

创建 20 个线程,模拟

package com.example.study;

/**
 * 
 * 
 * @author 李关钦
 * @date 2017年6月7日
 */
public class Test {

    public static void main(String[] args) {
        // 设置 20 个进程,模拟 20 个人订票
        for (int i = 0; i < 20; i++) {
            Thread thread = new Thread(new BuyTicketRunnable());
            thread.start();
        }
    }
}

结果:
这里写图片描述

从运行结果可以看到,线程 10 和线程 8 订票的结果一样了,也就说明了使用 synchronized 修饰的订票方法不起效,达不到互斥的效果。

原因:
在以上代码中,每创建一个订票线程 BuyTicketRunnabl创建一个 TicketManager 订票管理对象与之对应,也就是说创建了 20 个订票线程就会有 20 个对应的订票管理对象去操作票数,所以达不到互斥的关系。

解决方法:
在订票线程中用 static 修饰订票管理对象,使订票管理对象成为全局变量,与其他线程共享,所以 创建的 20 个线程就会共享同一个 TicketManager 订票管理对象,而 TicketManager 里面的订票方法又是使用 synchronized 的,所以就会达到互斥的效果。

package com.example.study;


/**
 * 订票线程,实现 Runnable 接口
 * 
 * @author 李关钦
 * @date 2017年6月7日
 */
public class BuyTicketRunnable implements Runnable {

    private static TicketManager ticketManager = new TicketManager();

    @Override
    public void run() {

        ticketManager.buyTicket();

    }

}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值