多线程卖票问题

1.实现多线程卖票

package com.cjj.duoxiancheng;

/*
* 路人假helloWorld
* 模拟卖票,三个窗口
* 存在线程的安全问题,待解决。
* */
class Window extends Thread{
    //设置总票数100张
    private static int ticket = 100;

    @Override
    public void run() {
        while(ticket > 0){
            System.out.println(Thread.currentThread().getName()+"买票,票号为:" + ticket);
            ticket--;
        }
    }
}

public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

}

运行结果如图:

可以看出100号票卖出了三张,证明程序存在线程安全问题。

2.解决方式

2.1 同步代码块

1.实现Runnable接口,可使用this作为锁

/*
*路人假helloWorld
*/
class Window1 implements Runnable{
    private int ticket = 100;
//    Object obj = new Object();

    @Override
    public void run() {
        while(true) {
            synchronized(this ) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}

public class WindowTest1 {
    public static void main(String[] args) {
        Window1 window1 = new Window1();

        Thread t1 = new Thread(window1);
        Thread t2 = new Thread(window1);
        Thread t3 = new Thread(window1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

2.继承Thread类,使用的锁必须也是静态对象

class Window extends Thread{
    //设置总票数100张
    private static int ticket = 100;
    static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
            synchronized(obj){
                if (ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

}

2.2 同步方法

关于同步方法的总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
2.
非静态的同步方法,同步监视器是: this ;
静态的同步方法,同步监视器是:当前类本身

1.实现Runnable接口

class Window2 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while(true) {
            show();
            if (ticket <= 0){
                break;
            }
        }
    }
    private synchronized void show(){
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

public class WindowTest2 {
    public static void main(String[] args) {
        Window2 window2 = new Window2();

        Thread t1 = new Thread(window2);
        Thread t2 = new Thread(window2);
        Thread t3 = new Thread(window2);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

2.继承Thread类

class Window3 extends Thread{
    //设置总票数100张
    private static int ticket = 100;
    @Override
    public void run() {
        while (true) {
            show();
            if (ticket <= 0){
                break;
            }
        }
    }
//必须是静态方法
    private static synchronized void show(){
        if (ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

public class WindowTest3 {
    public static void main(String[] args) {
        Window3 t1 = new Window3();
        Window3 t2 = new Window3();
        Window3 t3 = new Window3();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

}

3.3 Lock锁

创建ReentrantLock对象

/*
* 解决线程安全问题的方式三:Lock()锁    ---JDK5.0新增
*
* 1.面试题:synchronized 与 Lock的异同?
* 相同:二者都可以解决线程安全问题
* 不同:synchronized机制在执行完相应的同步代码后,自动释放同步监视器
*      Lock需要手动的启动同步监视器(lock()),同时结束同步也需要手动的实现(unlock())
*
* 2.优先使用顺序:
*   Lock --> 同步代码块(已经进入了方法体,分配了相应的资源) --> 同步方法(在方法体之外)
*
* 面试题:如何解决线程安全问题?有几种方式
*
* */

class LockWindow implements Runnable{

    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true) {
            try{
                //调用lock()上锁
                lock.lock();

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }finally{
                //调用unlock()解锁
                lock.unlock();
            }

        }
    }
}

public class LockWindowTest {

    public static void main(String[] args) {

        LockWindow window = new LockWindow();

        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}
posted @   路人假helloWorld  阅读(263)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
点击右上角即可分享
微信分享提示