本文已参与「新人创作礼」活动,一起开启掘金创作之路。
直接继承 Thread 类和实现 Runnable 接口都能实现多线程。
案例: 假设售票厅有四个窗口可发售某日某次列车的100张车票,这时,100张车票可以看作共享资源,四个售票窗口需要创建四个线程。为了更直观显示窗口的售票情况,可以通过Thread的currentThread()方法得到当前的线程实例对象,然后调用getName ()可以获取到线程的名称。
通过继承 Thread 类的方式来实现多线程的创建
程序:
public class ExampleM04 {
public static void main(String[] args) {
new TicketWindow().start(); //创建一个线程对象 TicketWindow()并start开启
new TicketWindow().start(); //创建一个线程对象 TicketWindow()并开启
new TicketWindow().start(); //创建一个线程对象 TicketWindow()并开启
new TicketWindow().start(); //创建一个线程对象 TicketWindow()并开启
}
}
class TicketWindow extends Thread {
private int tickets = 100;
public void run() {
while (true) { //死循环打印语句
if (tickets >0) {
Thread th = Thread.currentThread(); //获取当前线程
String th_name = th.getName(); //获取当前线程名字
System.out.println(th_name+"正在发售第"+tickets--+"张票");
}
}
}
}
每张车票都被打印了四次。出现这种现象的原因是四个线程没有共享100张票,而基名直出傅了100张票。在程序中创建了四个 Ticket Window 对象、就等于创建了四个售票程序,每个程序中都有100张票,每个线和在独立地处理各自的资源。
需要注意的是: 该情况每个线程都有自己的名学,主线程默认的名字是“ main ”,用户创建的第一个线程默认的名字为“ Thread —0”,第二个线程的野认名字为“ Thread —1”依此类推。如果希望指定线程的名称,则可以通过调用 setName ( String name )为线程设置名称。
通过实现 Runnable 接口的方式来实现多线程的创建
由于现实中铁路系统中的票资源是共享的,因此上面的运行结果显然不合理。为了保证资源共享,在程序中只能创建一个售票对象,然后开启多个线程去运行同一个售票对象的售票方法,简单来说就是四个线程运行同一个售票程序,这时就需要用到多线程的第二种实现方式。
程序
public class ExampleM05 {
public static void main(String[] args) {
TicketWindow02 tw02 = new TicketWindow02(); //创建实例对象
new Thread(tw02,"窗口1").start(); //创建线程对象并命名为窗口1,开启线程
new Thread(tw02,"窗口2").start(); //创建线程对象并命名为窗口2,开启线程
new Thread(tw02,"窗口3").start(); //创建线程对象并命名为窗口3,开启线程
new Thread(tw02,"窗口4").start(); //创建线程对象并命名为窗口4,开启线程
}
}
class TicketWindow02 implements Runnable {
private int tickets = 100;
public void run() {
while (true) { //死循环打印语句
if (tickets >0) {
Thread th = Thread.currentThread(); //获取当前线程
String th_name = th.getName(); //获取当前线程名字
System.out.println(th_name+"正在发售第"+tickets--+"张票");
}
}
}
}
该案例只创建了一个 Ticket Window 对象,然后创建了四个线程,在每个线程上都调用了这个 Ticket Window 对象中的 run ()方法,这样就可以确保四个线程访问的是同一个 tickets 变量,共享100张车票。
通过上面的两个例程可以看出,实现 Runnable 接口相对于继承 Thread 类来说,有如下显著的好处:
①适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好地体现了面向对象的设计思想。
②可以避免由于 Java 的单继承带来的局限性。在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承 Thread 类的方式,那么就只能采用实现 Runnable接口的方式。