`
liqita
  • 浏览: 290858 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java 创建线程的方法 继承Thread类和实现Runnable接口

阅读更多

要产生一个线程,有两种方法:

需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法;

实现Runnable接口,重载Runnable接口中的run()方法。

具体步骤

1、扩展Thread类来创建线程

首先,需要通过创建一个新类来扩展Thread类,这个新类就成为Thread类的子类。接着在该子类中重写Thread类的run()方法,此时方法体内的程序就是将来要在新建线程中执行的代码。

示例如下所示:

class SubThread extends Thread

{



public void run()

{

//
新建线程所要完成的工作

}



}

接着要创建该子类的对象,此时一个新的线程就被创建了,创建新线程时会用到Thread 类定义的如下两个构造函数:

◆public Thread()

◆public Thread(String name)

其中,第一个构造函数是Thread类默认的构造函数,不指定参数;第二个构造函数可以为新建的线程指定一个名称,该名称就是字符串参数name的值。

建立了新的线程对象以后,它并不运行,而是直到调用了该对象的start()方法,该方法在Thread 类中定义,在Thread 类的子类中被覆盖。它的作用是启动一个新的线程,并在该线程上运行子类对象中的run()方法。

start()方法声明格式为:

public void start()

示例如下所示:

SubThread s = new SubThread();   // 创建Thread子类的对象

s.start(); //
启动一个新的线程

当一个类继承Thread类时,它必须重写run()方法,这个方法是新线程的入口。如     Thread类的这个子类没有覆盖run()方法,那么程序会调用Thread类的run()方法,只    不过该run()方法什么也不做,此时新线程一创建就结束了。这种线程对程序来说是没有  任何意义的,所以在这里提醒读者在创建线程的时候一定不要忘了覆盖Thread类的run()方法。

下面举一个完整的例子来演示通过扩展Thread类创建线程的过程。程序代码如下所示:

// 4.1.1  ThreadDemo.java

class NewThread extends Thread  //
通过继承Thread类来创建一个新的线程

{

NewThread()//
构造方法

{    

super("Thread Demo");    //
定义线程的名字

System.out.println("New thread: " + getName());

}

public void run()  //
覆写run()方法,这是线程的入口

{  

while( true )

{

System.out.println(Thread.currentThread().getName()+

"  is running");

}

}

}

class ThreadDemo

{

public static void main(String args[])

{

NewThread thd = new NewThread(); //
创建一个新线程

thd.start();          //
启动线程,调用NewThread类对象的run()方法

}

}

可以看到,新的线程是由实例化NewThread类的对象创建的,该NewThread类可以通过继承java.lang.Thread类来得到。其中,在NewThread类中,构造函数里调用了super()方法。该方法将调用父类Thread下列形式的构造函数:

public Thread(String threadName)

这里,threadName指定线程名称(当然也可以不指定线程的名称,而由系统自动为新建线程提供名称)。在NewThread类中通过覆写 run()方法来规定线程所要实现的内容。此外,需要注意的是,启动新线程执行时必须调用start()方法。程序结果如图4.1.1所示:

Java创建线程的两种方法 - 娘子你就从了官人吧 -

在上面的代码中,使用了Thread类的currentThread()静态方法来获得当前程序执行时所对应的那个线程对象,又通过线程对象的 getName()方法,得到了当前线程的名字。这些方法都可以在JDK帮助文档中查到。因此,善于利用JDK帮助文档来获取有关类的更多信息,可以方便 程序的编写。

在上面代码的run()方法中,由于循环条件始终为true,因此,屏幕上会不断地输出Thread Demo is running,新建的线程永远不会结束,这当然不是所希望的结果。这里所希望的是可以合理的设置循环条件来有效地控制线程的终止。所以,在run()方 法中使用到循环控制的时候一定要小心使用,否则局面难以控制。

其实,针对前面的程序做一些改动。可以让这个程序实现一个非常有用的功能。

// 4.1.2  ThreadDemo2.java

class NewThread extends Thread //
通过继承Thread类来创建一个新的线程



NewThread(String name)   //
构造方法

{

super(name);

}

public void run()  //
重写run()方法,这是线程的入口

{

for( int i=10 ; i>0 ;i--)  //
循环执行10

{

try

{

System.out.println("left time: "+ i);

Thread.sleep(1000);   //
当前线程睡眠1000毫秒

}catch(InterruptedException e){     //
处理异常

System.out.println(e.getMessage());

}

}

System.out.println("game is over,bye!");

}

}

class ThreadDemo2

{

public static void main(String args[])

{

NewThread thd = new NewThread("Thread Demo"); //
创建一个新的线程

thd.start();          //
启动线程,调用NewThread类对象的run()方法

}

}

程序输出结果如图4.1.2 所示:

Java创建线程的两种方法 - 娘子你就从了官人吧 -

通过这个程序看到了什么?在run()方法体中,实现了一个倒计时的功 能。线程通过循环控制,每隔一秒输出一次剩余的时间,循环结束时输出"game is over,bye!",线程也随之结束。可见这个程序中新建的线程不是死循环,而是通过一些条件来对线程的起始进行了控制,从而实现了倒计时的功能。

在这个程序中,还可以看到,在给线程起名字的时候可以通过创建线程的时候来实现。因为查阅JDK的帮助文档,会发现Thread类除了默认的构造函 数之外,还有很多带参数的构造函数,只不过在这里是用到了public Thread(String name)这个构造方法。

并不是在创建线程对象的时候给线程起个名字就可以了,还应该在线程类的子类中定义相应的构造函数才行,这个构造函数的形式如下:

SubThread(String name)   // 线程子类的构造方法

{

super(name);

}

如果不这样做,程序编译会提示错误,读者可以想想为什么。也可以将上面程序中NewThread类的构造方法注释掉,编译一下程序,看到错误提示后,再去思考这个问题。

在这个程序中还用到了try…catch语句,它用来捕获程序中可能发生的异常,而产生异常的原因是程序中使用了Thread.sleep()这样的方法。通过查阅JDK的帮助文档,可以看到线程类的sleep()方法的完整格式如下:

public static void sleep(long millis) throws InterruptedException

看到这个throws关键字,想必读者就应知道为什么使用try…catch语句了。由于这个方法可能会抛出一个中断异常,因此,有必要在程序调用这个方法时对可能发生的异常进行处理。此外,这个方法是静态的,所以可以通过类名直接调用。

2、实现Runnable接口来创建线程

除了扩展Thread类可以创建线程之外,还可以通过定义一个实现了Runnable接口的类来创建线程。为了将来程序执行时可以进入线程,在这个类中必须实现Runnable接口中唯一提供的run()方法。

示例如下所示:

class OneThread implements Runnable

{



public void run()

{

//
新建线程所要完成的工作

}

}

当定义好一个实现了Runnable接口的类以后,还不能直接去创建线程对象,要想真正去创建一个线程,还必须在类的内部实例化一个Thread类的对象。此时,会用到Thread 类定义的如下两个构造函数:

public Thread(Runnable target)

public Thread(Runnable target,String name)

在这两个构造函数中,参数target定义了一个实现了Runnable接口的类的对象引用。新建的线程将来就是要执行这个对象中的run()方法。而新建线程的名字可以通过第二个构造方法中的参数name来指定。

示例如下所示:

OneThread onethread = new OneThread();

Thread newthread = new Thread(onethread);

此时,新线程对象才被创建,如果想要执行该线程的run()方法,则仍然需要通过调用start()方法来实现。例如:

newthread.start();

要想创建新的线程对象,这两条语句缺一不可。此后程序会在堆内存中实实在在地创建一个OneThread类的实例对象,该对象中包含了一个线程对象 newthreadnewthread对象会通过调用start()方法来执行它自己的run()方法。随着run()方法的结束,线程对象 newthread的生命也将结束,但是onethread对象还会存在于堆内存当中。如果希望在实际编程当中一旦线程结束,即释放与线程有关的所有资源,可以使用创建匿名对象的方法来创建这个线程,格式如下所示:

new Thread(new OneThread).start();

这样一来,该线程一旦运行结束,所有与该线程有关的资源都将成为垃圾,这样就可以在特定的时间内被Java的垃圾回收机制予以回收,释放所占用内存,提高程序的效率。

下面这个程序是通过实现Runnable接口来创建的线程,可以将它和前面的例4.1.2的程序进行比较。

// 4.1.3  ThreadDemo3.java

class NewThread implements Runnable //
实现了Runnable接口



public void run() //
覆写Runnable 接口中唯一的run()方法,这是线程的入口

{

for( int i=10 ; i>0 ;i--)

{

try

{

System.out.println("left time: "+ i);

Thread.sleep(1000);   //
当前线程睡眠1000毫秒

}catch(InterruptedException e){     //
处理异常

System.out.println(e.getMessage());

}

}

System.out.println("game is over,bye!");

}

}

class ThreadDemo3

{

public static void main(String args[])

{

NewThread newthread = new NewThread();

Thread thd = new Thread(newthread, "Thread Demo")

thd.start();          //
启动线程,调用run()方法

}

}

编译并运行这个程序,可以看到程序执行的结果和例4.1.2的程序输出的结果是完全一样的,因此,读者可以在创建线程的时候选择任意一种方式来实现

为了使程序达到优异的性能,可以利用创建线程来完成那些任务。因为一个线程就是一个独立的执行通道,在没有特殊的要求之下,多个线程之间彼此独立运行,互不干扰。而且带线程的程序通常比没有带线程的程序运行得要快,因此线程常 用在网络和图形用户界面等程序设计当中,这一优势在多处理器的计算机上更加明显。本节中不仅要理解什么是线程,而且还应掌握两种创建线程的方法,为以后在程序中使用多线程技术打下坚实的基础。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics