public class Ticket implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖了一张票,剩下:" + ticket--);
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
Thread t3 = new Thread(ticket, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
此时会出现线程安全问题,可以加锁解决此问题
public class Ticket implements Runnable {
private int ticket = 100;
@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--);
}
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Ticket ticket1 = new Ticket();
Ticket ticket2 = new Ticket();
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket1, "窗口2");
Thread t3 = new Thread(ticket2, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
咦?还是出现了线程安全问题,这是为什么呢?
有细心的同学想必发现了我第二个代码new了两个类,分别是
Ticket ticket1 = new Ticket(); Ticket ticket2 = new Ticket();
我们知道在java中每实例化一次就会在计算机内存中开辟一块新的内存空间,而我们的锁只锁住了
Ticket ticket = new Ticket();
,而后两者没有锁住所以可以访问到内存空间进行
ticket--操作导致数据被重复消费。我们需要做两步操作才能彻底保证数据安全性。第一:在
synchronized括号里加入类名.class例如
synchronized (Ticket.class)。第二:在变量前加上
static