多线程(让你学习怎么卖车票)

本文参考: Java 多线程详解(三)------线程的同步
作者YSOcean

模拟场景:火车站卖票,50张票,分三个窗口进行售卖(三个线程)

问题抛出

第一种方式:继承Thread类

public class TicketSellByThread extends Thread {
    //定义一共有 50 张票,注意声明为 static,表示几个窗口共享
    public static  int num = 50;

    public TicketSellByThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(num>0){
                //让线程休息一秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //打印余票数量
                System.out.println(currentThread().getName()+"卖出一张票,剩余"+(--num)+"票");
            }
        }
    }

    public static void main(String[] args) {
        TicketSellByThread t1 = new TicketSellByThread("窗口A");
        TicketSellByThread t2 = new TicketSellByThread("窗口B");
        TicketSellByThread t3 = new TicketSellByThread("窗口C");

        t1.start();
        t2.start();
        t3.start();
    }
}

多线程(让你学习怎么卖车票)_第1张图片
继承Thread类.png

出现的问题:会出现票数有负数和两个窗口余票数量相同的情况的情况

第二种方式:实现Runnable接口

public class TicketSellByRunable implements Runnable{

    //定义一共有 50 张票,注意声明为 static,表示几个窗口共享
    public int num = 50;

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(num>0){
                //让线程休息一秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //打印余票数量
                System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"票");
            }
        }
    }
    
    public static void main(String[] args) {
        TicketSellByRunable ticketSellByRunable = new TicketSellByRunable();

        Thread t1 = new Thread(ticketSellByRunable,"窗口A");
        Thread t2 = new Thread(ticketSellByRunable,"窗口B");
        Thread t3 = new Thread(ticketSellByRunable,"窗口C");

        t1.start();
        t2.start();
        t3.start();
    }

}

多线程(让你学习怎么卖车票)_第2张图片
实现Runnable接口.png

出现的问题:出现了两个窗口剩余票数一样的情况!

解决办法分析:

不能同时让超过两个以上的线程进入到 if(num>0)的代码块中,不然就会出现上述的错误。

3.解决办法:

  • 1、使用 同步代码块
  • 2、使用 同步方法
  • 3、使用 锁机制

3.1同步代码块

  • 同步代码块
语法:
synchronized (同步锁) {
    //需要同步操作的代码         
}
 
同步锁:为了保证每个线程都能正常的执行原子操作,Java 线程引进了同步机制;同步锁也叫同步监听对象、同步监听器、互斥锁;
Java程序运行使用的任何对象都可以作为同步监听对象,但是一般我们把当前并发访问的共同资源作为同步监听对象
 
注意:同步锁一定要保证是确定的,不能相对于线程是变化的对象;任何时候,最多允许一个线程拿到同步锁,谁拿到锁谁进入代码块,而其他的线程只能在外面等着
  @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            synchronized (this.getClass()) {
                if (num > 0) {
                    //让线程休息一秒
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //打印余票数量
                    System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余" + (--num) + "票");
                }
            }
        }
    }
多线程(让你学习怎么卖车票)_第3张图片
同步代码块.png

3.2同步方法

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            sell();
        }
    }


    public synchronized void sell(){
        if (num > 0) {
            //让线程休息一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //打印余票数量
            System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余" + (--num) + "票");
        }
    }
多线程(让你学习怎么卖车票)_第4张图片
同步方法.png

 注意:不能直接用 synchronized 来修饰 run() 方法,因为如果这样做,那么就会总是第一个线程进入其中,而这个线程执行完所有操作,即卖完所有票了才会出来。

3.3锁机制

    public int num = 50;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            l.lock();
            try {
                if (num > 0) {
                    //让线程休息一秒
                    Thread.sleep(1000);
                    //打印余票数量
                    System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余" + (--num) + "票");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                l.unlock();
            }
        }
    }
多线程(让你学习怎么卖车票)_第5张图片
image.png

你可能感兴趣的:(多线程(让你学习怎么卖车票))