要产生数据安全问题,得符合三个条件
1.是否是多线程环境
2.是否多个线程有共享数据
3.是否有多条语句在操作共享数据 piao-- 读 改 写 先使用 后运算 再写
在多线程环境下出现了数据异常,我们称之为多线程下数据安全问题。
1.出现了重复票:是由于piao-- 不是原子性的操作所导致的 – ++
2.出现了0票和负数票:这个是由于线程的随机性导致的
实例代码
public class MyTest {
public static void main(String[] args) {
/* A:
案例演示
需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
通过继承Thread类实现
三个窗口相当于三个线程
买票过程中会有网络延迟现象,我们模拟一下网络延迟
*/
SellTicketsThread th1 = new SellTicketsThread();
SellTicketsThread th2= new SellTicketsThread();
SellTicketsThread th3 = new SellTicketsThread();
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
//要产生数据安全问题,得符合三个条件
//1.是否是多线程环境
//2.是否多个线程有共享数据
//3.是否有多条语句在操作共享数据 piao-- 读 改 写 先使用 后运算 再写
//在多线程环境下出现了数据异常,我们称之为多线程下数据安全问题。
//1.出现了重复票:是由于piao-- 不是原子性的操作所导致的 -- ++
//2.出现了0票和负数票:这个是由于线程的随机性导致的
//我们可以使用同步代码块
/* synchronized (同步锁){
//放出现线程安全问题的代码
}
*/
}
}
public class SellTicketsThread extends Thread {
static int piao = 100; //这个票数是多个线程的共享数据
static Object obj=new Object();
int i=1;
@Override
public void run() { //th1 th2 th3
while (true){
if(i%2==0){
//假如就剩1张票了 th1 th2
// th2 th3 th1
synchronized (this) { //同步代码块的锁,可以使用Java的任意的一个对象 多个线程要共用一把锁
//th1 进入同步代码块获取锁
if (piao > 0) {
try {
//模拟网络延迟
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName() + ":正在出售" + (piao--) + "张票");//th1
}
}
//出了同步代码块 th1 释放锁
}else{
maipiao();
}
i++;
}
}
private synchronized void maipiao(){
String name = this.getClass().getName();
System.out.println(name);
//同步代码块的锁,可以使用Java的任意的一个对象 多个线程要共用一把锁
//th1 进入同步代码块获取锁
if (piao > 0) {
try {
//模拟网络延迟
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName() + ":正在出售" + (piao--) + "张票");//th1
}
}
}
public class SellRunnable implements Runnable {
static int piao = 100;
static Object obj = new Object();
int i = 1;
@Override
public void run() {
while (true) {
if (i % 2 == 0) {
// maiPiao();
synchronized (SellRunnable.class) {
if (piao > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":正在出售" + (piao--) + "张票");
}
}
} else {
maiPiao2();
}
i++;
}
}
//同步方法使用锁对象是this
private synchronized void maiPiao() {
if (piao > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":正在出售" + (piao--) + "张票");
}
}
//静态同步方法使用的锁对象,是字节码对象
private synchronized static void maiPiao2() {
if (piao > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":正在出售" + (piao--) + "张票");
}
}
}