使用实例进行辨析
示例:设售票厅有四个窗口可发售某日某次列车的100张车票,这时,100张车票可以看作共享资源,四个售票窗口需要创建四个线程。下面分别通过继承Thread类和实现Runnable接口的方式实现多线程创建。
1、继承Thread类
public class Ticket extends Thread{
//定义火车票数量
private int tickets = 100;
//定义发售火车票的窗口名字
private String name;
//构造器
public Ticket(String name) {
this.name = name;
}
@Override
public void run() {
//使用死循环打印输出语句
while (true){
if (tickets > 0) {
System.out.println(name+"正在发售第"+(tickets--)+"张票");
}else break;
}
}
}
创建测试类:
public class Example03 {
//1、创建四个Ticket对象
public static void main(String[] args) {
//定义四个线程对象,代表四个售票窗口
Ticket ticket1 = new Ticket("票口1");
Ticket ticket2 = new Ticket("票口2");
Ticket ticket3 = new Ticket("票口3");
Ticket ticket4 = new Ticket("票口4");
//启动线程
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
运行结果:使用command+F进行查找发现有四个打印结果
即给每个窗口均创建了100张车票,这显然与现实不符!接下来我们使用Runnable接口
2、Runnable接口
public class Ticket implements Runnable{
//定义初始火车票
private int tickets = 100;
@Override
public void run() {
//死循环打印语句
while (true){
if (tickets>0){
//获得当前线程名
String name = Thread.currentThread().getName();
System.out.println(name+"正在发售第"+(tickets--)+"张票");
}else break;
}
}
}
创建测试类
public class Example03 {
public static void main(String[] args) {
//创建任务对象[总共100张票,四个窗口发售]
Ticket ticket = new Ticket();
//创建四个线程对象
Thread t1 = new Thread(ticket,"票口1");
Thread t2 = new Thread(ticket,"票口2");
Thread t3 = new Thread(ticket,"票口3");
Thread t4 = new Thread(ticket,"票口4");
//启动线程
t1.start();
t2.start();
t4.start();
t3.start();
}
}
运行结果:使用command+F进行查找发现只有一个打印结果
3、结果对比:
1、使用Thread继承类的时候,100张票在每个窗口都输出了一次。原因是因为这四个线程并没有共享 100张票。在程序中创建4个Ticket对象,相当于创建了四个售票程序,每个程序中均有100张票,每个线程独立处理个自的资源。
2、使用Runnable接口的时候,四个线程访问的是同一个tickets变量,实现了100张车票的共享。
3、由此可得Runnable接口相较于Thread继承类的优势有如下两点:
3.1、适合多个程序代码相同的线程处理同一资源的情况
3.2、避免了由于Java的单继承特性带来的局限性。
推荐在实际开发中,使用实现Runnable接口方式创建多线程。