通过继承thread
public class SaleTicket extends Thread{
static int num = 40;
static Object object = new Object();
public SaleTicket(String name){
super(name);
}
public void run(){
while(true){
//这里为什么用object对象,下面会讲到
synchronized(object){
if(num<=0){
System.out.println("票已经卖完");
System.exit(1);
}
else{
System.out.println(Thread.currentThread().getName()+"卖出一张票,还剩"+ --num);
try{
Thread.sleep(50);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
public static void main(String args[]){
SaleTicket s1 = new SaleTicket("窗口一");
SaleTicket s2 = new SaleTicket("窗口二");
SaleTicket s3 = new SaleTicket("窗口三");
s1.start();
s2.start();
s3.start();
}
}
通过实现Runnable接口
public class SaleTicket2 implements Runnable {
private int num = 40;
public SaleTicket2(){}
public void run(){
while(true){
synchronized(this){
if(num<=0){
System.out.println("票已经卖完");
System.exit(0);
}
else{
System.out.println(Thread.currentThread().getName()+"卖出一张票,还剩"+ --num);
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
}
public static void main(String args[]){
SaleTicket2 saleTicket2 = new SaleTicket2();
Thread t1 = new Thread(saleTicket2,"窗口一");
Thread t2 = new Thread(saleTicket2,"窗口二");
Thread t3 = new Thread(saleTicket2,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
这里解释一下为什么在实现Runnable接口时,可以使用 synchronized (this),而在继承Thread中必须声明静态成员来作为锁的对象。当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。换句话说,在实现Runnable接口时,this指代的是当前类的对象,上文中的saleTicket2 是SaleTicket2的实例对象,在创建多个线程的时候,这些线程公用一个锁的对象(saleTicket2),所以就可以实现同步。而在继承Thread类中,SaleTicket创建了4个线程来模拟窗口,如果用this,系统会认为哪个线程访问,对应线程的SaleTicket的实例就作为锁的对象,导致了会产生4个锁的对象,因此同步失败。所以在要用static修饰一个对象, 来保证锁的对象唯一性。