java 多线程以及线程锁(synchronized )的使用

时间:2021-07-25 13:06:45

使用java 多线程模拟 火车票售票系统。 要求是,有三个火车票售票点。他们都是从 同一个铁路局里面拿的票, 假设铁路局一共有 2000 张票 , 三个售票点要一起出售这2000张票。
这个题目就会遇到一个线程安全的问题了,由于多个线程是共享内存的,当我们使用多个线程去操作同一个数据时就会遇到得出的数据不是我们预期的结果。
比如我们现在这样做的 售票系统

package Threading;

/** * 使用java 多线程模拟 火车票售票系统。 要求是,有三个火车票售票点。 * 他们都是从 同一个铁路局里面拿的票, 假设铁路局一共有 2000 张票 , * 三个售票点要一起出售这2000张票。 * Created by admin on 2017/8/5. */
public class TicketingSystem {
    public static void main(String[] args){
        Windows ticketWindow = new Windows();
        // 定义三个售票窗口
        Thread ticketWindow1 = new Thread(ticketWindow);
        Thread ticketWindow2 = new Thread(ticketWindow);
        Thread ticketWindow3 = new Thread(ticketWindow);
        ticketWindow1.start();
        ticketWindow2.start();
        ticketWindow3.start();
    }

}

class Windows implements Runnable{
    private int freeTicket = 2000;
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            if (freeTicket>0){

                System.out.println(Thread.currentThread().getName() + "在出售第" + freeTicket + "张票");
                freeTicket --;
            }
            else {
                break;
            }
        }

    }

}

就会遇到 比如下面截图的问题, 线程 0 和 线程 1 同时出售了 第 1988 张 票, 这个就是由于多线程
共享内存的关系, 线程 0 和线程 1 同时拿到了 1988号的票, 因为我们在里面加了一个休眠,
当线程 0 拿到 1988 号的票是,就被休眠了还没来得及 进行 freeTicket –;,然后线程 1 又马上过来了。此时 线程 1 拿到的也是 1988
java 处理线程安全的方法也是加锁,使用 synchronized(Object) { 需要线程安全的代码放到这里 }

java 多线程以及线程锁(synchronized )的使用

因此上面的代码需要加线程锁,应该改为 如下:

package Threading;

/** * 使用java 多线程模拟 火车票售票系统。 要求是,有三个火车票售票点。 * 他们都是从 同一个铁路局里面拿的票, 假设铁路局一共有 2000 张票 , * 三个售票点要一起出售这2000张票。 * Created by admin on 2017/8/5. */
public class TicketingSystem {
    public static void main(String[] args){
        Windows ticketWindow = new Windows();
        // 定义三个售票窗口
        Thread ticketWindow1 = new Thread(ticketWindow);
        Thread ticketWindow2 = new Thread(ticketWindow);
        Thread ticketWindow3 = new Thread(ticketWindow);
        ticketWindow1.start();
        ticketWindow2.start();
        ticketWindow3.start();
    }

}

class Windows implements Runnable{
    // 存在的问题, 多个线程共享内存,当同时需要操作同一个数据时,就需要加线程锁
    private int freeTicket = 2000;
    @Override
    public void run() {
        while (true){
            // 需要在此处加锁
            synchronized (this){
            if (freeTicket>0){
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "在出售第" + freeTicket + "张票");
                freeTicket --;
            }
            else {
                break;
            }}
        }

    }

}

synchronized 属于互斥锁,当有一个线程锁定了之后,其他线程只能等待 出了 synchronized 代码块之后,又会变成并发了