线程安全问题

线程安全问题

多个线程执行的 不确定性, 引起执行结果的不稳定

多个线程, 对账本的共享, 会造成 操作的不完整性, 会破坏数据

创建3个窗口买票, 总票数为为100张, 使用实现Runnable接口的方式

1. 卖票过程中, 出现 重票, 错票, 出现了线程安全问题

问题出现的原因

当某个线程操作 车票 的过程中, 尚未操作完成时, 其他线程参与进来, 也操作车票

2. 解决方法

当一个线程a在操作 ticket 的时候, 其他线程不能参与进来

直到线程a 操作完 ticket时, 线程才可以开始操作 ticket, 这种情况即使 线程a 出现了阻塞, 也不能改变

在Java中, 通过 同步机制, 来解决的安全问题

2.1. 最初的方法

2.1.1. 同步代码块

synchronized(同步监视器) {
    // 需要被同步的代码
}

什么叫 需要被同步的代码?

操作 共享数据的代码, 即为 需要被同步的代码

共享数据: 多个线程 共同操作 的变量, 比如 ticket 就是 共享数据

同步监视器, 俗称 锁,

任何一个类的对象, 都可以充当 锁

要求: 多个线程 必须要共用 同一把锁 (不能一个人, 一个锁)

class Windows1 implements Runnable{

    private int ticket = 100;
    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;
            }

        }
    }
  }
}

class WindowsTest1 {
    public static void main(String[] args) {
        Windows1 w = new Windows1();

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

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

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

2.1.2. 同步方法

class Window2 extends Thread {
    private static int ticket = 100;
//    private static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (Window2.class) {
                if (ticket > 0) {

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(getName() + ": 卖票, 票号为: " + ticket);
                    ticket--;

                } else {
                    break;
                }
            }
        }
    }
}

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

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

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

3. jdk5新增的解决方法

参考链接

posted on   beyondx  阅读(44)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示