其他分享
首页 > 其他分享> > 多线程(四)-线程同步

多线程(四)-线程同步

作者:互联网

大佬的理解-> Java多线程(三)--synchronized关键字详情

大佬的理解-> Java多线程(三)--synchronized关键字续

1、问题引入

买票问题

1.1 通过继承Thread买票

继承Thread买票案例

/*
    模拟网络购票,多线程资源共享问题,继承Thread方式;
    结论:此种方式,不存在资源共享,通过创建对象启动的线程,每个对象都有各自的属性值
 */
public class MyThreadTicket extends Thread{

    //总票数
    private int remainSite = 100;

    //抢到的座位号
    private int buySite = 0;

    @Override
    public void run() {
        //模拟循环抢票
        while(true){
            //判断余票是否充足,如果不足,结束
            if(remainSite <= 0){
                break;
            }

            //更改强股票数据
            buySite++;
            remainSite--;

            //模拟网络延迟
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"买到第"+buySite+"张票,剩余"+remainSite+"张票");
        }
    }

    public static void main(String[] args) {
        //模拟三人同事抢票
        MyThreadTicket threadTicket1 = new MyThreadTicket();
        threadTicket1.setName("猪八戒");
        MyThreadTicket threadTicket2 = new MyThreadTicket();
        threadTicket2.setName("沙和尚");
        MyThreadTicket threadTicket3 = new MyThreadTicket();
        threadTicket3.setName("孙猴子");

        System.out.println("---抢票开始---");
        threadTicket1.start();
        threadTicket2.start();
        threadTicket3.start();

    }
}

运行结果

---抢票开始---
猪八戒买到第1张票,剩余99张票
孙猴子买到第1张票,剩余99张票
沙和尚买到第1张票,剩余99张票
孙猴子买到第2张票,剩余98张票
猪八戒买到第2张票,剩余98张票
沙和尚买到第2张票,剩余98张票
孙猴子买到第3张票,剩余97张票
沙和尚买到第3张票,剩余97张票
猪八戒买到第3张票,剩余97张票
猪八戒买到第4张票,剩余96张票
沙和尚买到第4张票,剩余96张票
孙猴子买到第4张票,剩余96张票
孙猴子买到第5张票,剩余95张票
......
孙猴子买到第99张票,剩余1张票
猪八戒买到第99张票,剩余1张票
沙和尚买到第99张票,剩余1张票
孙猴子买到第100张票,剩余0张票
猪八戒买到第100张票,剩余0张票
沙和尚买到第100张票,剩余0张票

出现的问题

每个人都买了100张票,没有共享数据;

1.2 通过实现Runnable接口买票

实现Runnable接口案例

/*
    模拟网络购票,实现Runnable方法
 */
public class MyRunnableTicket0 implements Runnable{
    //总票数
    private int remainSite = 100;

    //抢到的座位号
    private int buySite = 0;

    @Override
    public void run() {
        //模拟循环抢票
        while(true){
            //判断余票是否充足,如果不足,结束
            if (remainSite <= 0) {
                break;
            }

            //更改强股票数据
            buySite++;
            remainSite--;

            //模拟网络延迟
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "买到第" + buySite + "张票,剩余" + remainSite + "张票");
        }

    }

    public static void main(String[] args) {
        //创建三个子线程
        MyRunnableTicket0 runnableTicket = new MyRunnableTicket0();
        Thread thread1 = new Thread(runnableTicket,"哪吒");
        Thread thread2 = new Thread(runnableTicket,"金吒");
        Thread thread3 = new Thread(runnableTicket,"木吒");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果

木吒买到第96张票,剩余4张票
哪吒买到第96张票,剩余4张票
金吒买到第96张票,剩余4张票
木吒买到第99张票,剩余1张票
哪吒买到第99张票,剩余1张票
金吒买到第99张票,剩余1张票
木吒买到第100张票,剩余0张票

出现的问题

共享了数据,但是出现了漏票,和几个人买同一张票的情况;

2、解决方法

通过synchronized同步锁来进行同步,使同一时间只有一个人在买票;

2.1 同步代码块

同步代码块案例

/*
    模拟网络购票,实现Runnable方法
    同步代码块方法
 */
public class MyRunnableTicket implements Runnable{
    //总票数
    private int remainSite = 100;

    //抢到的座位号
    private int buySite = 0;
    //同步代码块
    @Override
    public void run() {
        //模拟循环抢票
        while(true){
            //同步代码快
            synchronized (this) {
                //判断余票是否充足,如果不足,结束
                if (remainSite <= 0) {
                    break;
                }

                //更改强股票数据
                buySite++;
                remainSite--;

                //模拟网络延迟
                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "买到第" + buySite + "张票,剩余" + remainSite + "张票");
            }
        }
    }

    public static void main(String[] args) {
        //创建三个子线程
        MyRunnableTicket runnableTicket = new MyRunnableTicket();
        Thread thread1 = new Thread(runnableTicket,"哪吒");
        Thread thread2 = new Thread(runnableTicket,"金吒");
        Thread thread3 = new Thread(runnableTicket,"木吒");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果

哪吒买到第1张票,剩余99张票
哪吒买到第2张票,剩余98张票
哪吒买到第3张票,剩余97张票
哪吒买到第4张票,剩余96张票
哪吒买到第5张票,剩余95张票
......
金吒买到第96张票,剩余4张票
金吒买到第97张票,剩余3张票
金吒买到第98张票,剩余2张票
金吒买到第99张票,剩余1张票
金吒买到第100张票,剩余0张票

可以正常买票,问题解决;

2.2 同步方法

同步方法案例

/*
    模拟网络购票,实现Runnable方法
    同步方法
 */
public class MyRunnableTicket implements Runnable{
    //总票数
    private int remainSite = 100;

    //抢到的座位号
    private int buySite = 0;

    @Override
    public void run() {
        //模拟循环抢票
        while(remainSite > 0){

            //调用同步购买方法
            buyTicket();

            //模拟网络延迟
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    /*
        同步方法
        增加同步锁,限制多线程场景下,只允许一个线程执行当前方法,确保票数修改正确
     */
    public synchronized void buyTicket(){
        //判断余票是否充足,如果不足,结束
        if(remainSite <= 0){
            return;
        }

        //更改强股票数据
        buySite++;
        remainSite--;

        System.out.println(Thread.currentThread().getName()+"买到第"+buySite+"张票,剩余"+remainSite+"张票");
    }

运行结果

哪吒买到第1张票,剩余99张票
哪吒买到第2张票,剩余98张票
哪吒买到第3张票,剩余97张票
哪吒买到第4张票,剩余96张票
哪吒买到第5张票,剩余95张票
......
金吒买到第96张票,剩余4张票
金吒买到第97张票,剩余3张票
金吒买到第98张票,剩余2张票
金吒买到第99张票,剩余1张票

可以正常买票,问题解决;

标签:剩余,金吒买,买到,同步,张票,99,线程,100,多线程
来源: https://www.cnblogs.com/xiaoqigui/p/16396916.html