Java两种方法实现模拟卖票
创建线程常用的两种方式,一是实现Runnable接口,二是继承Thread类,都需要重写run()方法。
第一种继承Thread类
public class TestThread extends Thread{
//定义全局变量i,这里要4个窗口共享
private static int i = 40;
//定义静态对象 object,保证在使用时synchronized获得对象的唯一性
static private Object object=new Object();
//定义线程名称
public TestThread(String name) {
super(name);
}
@Override
public void run(){
while (true){
//这里不能用this,原因下面解释
synchronized(object){
if(i==0){
System.out.println("票已售完,请下次再来!!");
System.exit(1);
}else {
System.out.println(Thread.currentThread().getName() + " 售出第 " + (40- --i) + " 张票");
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws Exception {
TestThread mt1 = new TestThread("窗口1");
TestThread mt2 = new TestThread("窗口2");
TestThread mt3 = new TestThread("窗口3");
TestThread mt4 = new TestThread("窗口4");
mt1.start();
mt2.start();
mt3.start();
mt4.start();
}
}
输出如下:
第二种实现Runnable接口
public class TestRunnable implements Runnable {
//定义票的总数
private int total = 20;
//定义票的编号
private int no = total+1;
@Override
public void run() {
while (true) {
//同步锁
synchronized (this) {
if (total > 0) {
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
String msg = Thread.currentThread().getName() + " 售出第 " + (no - total) + " 张票";
System.out.println(msg);
total--;
} else {
System.out.println("票已售完,请下次再来!");
System.exit(0);
}
}
}
}
public static void main(String[] args) {
TestRunnable std=new TestRunnable();
//把对象放入线程中
Thread t1 = new Thread(std,"售票窗口1");
Thread t2 = new Thread(std,"售票窗口2");
Thread t3 = new Thread(std,"售票窗口3");
Thread t4 = new Thread(std,"售票窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
输出如下:
这里解释一下为什么在实现Runnable接口时,可以使用 synchronized (this),而在继承Thread中必须声明静态成员来作为锁的对象。当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。换句话说,在实现Runnable接口时,this指代的是当前类的对象,上文中的std是TestRunnable 的实例对象,在创建多个线程的时候,这些线程公用一个锁的对象(std),所以就可以实现同步。而在继承Thread类中,TestThread 创建了4个线程来模拟窗口,如果用this,系统会认为哪个线程访问,对应线程的TestThread的实例就作为锁的对象,导致了会产生4个锁的对象,因此同步失败。所以在要用static修饰一个对象, 来保证锁的对象唯一性。