卖票案例---三种方式保持线程安全
普通的卖票系统
线程类每10毫秒卖一张票,有三个人同时买
public class MyRunnable1 implements Runnable{
private int t=1;//多线程共享的资源
@Override
public void run() {
while(true){
if (t <=100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + t + "张票");
t++;
}
}
}
}
测试类
public static void main(String[] args) {
MyRunnable1 mr=new MyRunnable1();
Thread t1=new Thread(mr) ;
Thread t2=new Thread(mr) ;
Thread t3=new Thread(mr) ;
t1.start();
t2.start();
t3.start();
}
结果:
会出现卖乱卖票和卖多了票的情况
要避免这种情况,保证线程安全,就有下面三种方式
第一种(通过synchronized,传入一个对象,让线程得到那个对象时才能运行)
public class MyRunnable1 implements Runnable{
private int t=1;//多线程共享的资源
Object obj=new Object();//创建一个所对象,让线程互斥。看这里
@Override
public void run() {
while(true){
synchronized (obj) {//看这里
if (t <=100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + t + "张票");
t++;
}
}
}
}
}
创建一个object对象在while中添加一条synchronized (obj){}
注意颜色,这跟while和if同一个颜色
第二种方式通过函数来保证线程安全
public class MyRunnable2 implements Runnable{
private static int t=1;//多线程共享的资源
public synchronized void a1(){//看这里
if (t <=100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + t + "张票");
t++;
}
}
@Override
public void run() {
while(true){
a1();//看这里
}
}
}
还是跟synchronized有关==
第三种通过创建ReentrantLock 对象调用它的lock和unlock来(这个不会出现synchronized)
public class MyRunnable3 implements Runnable{
private static int t=1;//多线程共享的资源
ReentrantLock rl=new ReentrantLock();//这里需要创建一个ReentrantLock 对象。看这里
@Override
public void run() {
while(true){
rl.lock();//锁上。看这里
if (t <=100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
rl.unlock();//出异常时也能开锁
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + t + "张票");
t++;
}
rl.unlock();//开锁。看这里
}
}
}