我们先来写一个买票程序
我们先创建一个包 在包下创建两个类
customException 线程类 负责编写抢票的主要逻辑
参考代码如下
public class customException implements Runnable {
private int tickets = 100;
public void run () {
while (tickets > 0){
if(tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
text 测试类 用于实例化线程对象 并执行线程
public class text {
public static void main(String args[]) {
Runnable Runnable = new customException();
Thread m1 = new Thread(Runnable,"客户");
Thread m2 = new Thread(Runnable,"黄牛");
Thread m3 = new Thread(Runnable,"导爷");
m1.start();
m2.start();
m3.start();
}
}
然后 我们运行代码
我们会发现 第一百张票被抢了三次
负一也出来啦 这就是我们要解决的问题 线程执行随机性导致同一张票出售多次
科普个知识
java有特意为此现象 定义了数据安全性的描述
那么 显然 我们不是一个单线程 而是多线程 第一条 我们是到达了不安全的条件的
我们有一个tickets共享数据 所以 第二个条件 我们也是达到了不安全条件的
第三个 我们确实是在线程中 操作了 tickets 共享数据 tickets –
所以 这三个条件我们都达到了不安全的条件
java提供了 synchronized 锁方法解决这个问题 接受一个对象参数
这里 我们将customException 的 run方法修改代码如下
public void run () {
while (tickets > 0){
synchronized (new Object()) {
if(tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
此时 我们调用了synchronized 将操作公共数据的代码锁了起来 运行结果如下
但很明显 问题并没有解决 因为我们传递对象是在方法中定义的 每个线程进来 看到的锁都是不一样的
那么 我们可以写一个公共的对象来锁
customException类代码修改如下
public class customException implements Runnable {
private int tickets = 100;
private Object obj = new Object();
public void run () {
while (true){
synchronized (obj) {
if(tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
}
这里我们直接定义了一个叫 obj 的公共对象 来定义同步锁
然后我们执行代码
可以看到 我们的数据已经是正常的执行了 这就解决了我们上述的问题