黑马程序员_线程基础 (一)

2014-11-24 11:44:58 · 作者: · 浏览: 45

一、概述

由于Java是纯面向对象语言,因此,Java的线程模型也是面向对象的。Java通过Thread类将线程所必须的功能都封装了起来。要想建立一个线程,必须要有一个线程执行函数,这个线程执行函数对应Thread类的run方法。Thread类还有一个start方法,这个方法负责建立线程。当调用start方法后,如果线程建立成功,并自动调用Thread类的run方法。因此,任何继承Thread的Java类都可以通过Thread类的start方法来建立线程。如果想运行自己的线程执行函数,那就要覆盖Thread类的run方法。

在Java的线程模型中除了Thread类,还有一个标识某个Java类是否可作为线程类的接口Runnable,这个接口只有一个抽象方法run,也就是Java线程模型的线程执行函数。因此,一个线程类的唯一标准就是这个类是否实现了Runnable接口的run方法,也就是说,拥有线程执行函数的类就是线程类。

从上面可以看出,在Java中建立线程有两种方法,一种是继承Thread类,另一种是实现Runnable接口,并通过Thread和实现Runnable的类来建立线程,其实这两种方法从本质上说是一种方法,即都是通过Thread类来建立线程,并运行run方法的。但它们的大区别是通过继承Thread类来建立线程,虽然在实现起来更容易,但由于Java不支持多继承,因此,这个线程类如果继承了Thread,就不能再继承其他的类了,因此,Java线程模型提供了通过实现Runnable接口的方法来建立线程,这样线程类可以在必要的时候继承和业务有关的类,而不是Thread类。


二、介绍

从java的API开始,因为Runnable是顶层接口,所以先说一下它。API中是这样说明的:Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。

通过说明我们知道,要想使用Runnable来创建线程,实现Runnable接口的类必须使用Thread类的实例才能创建线程。通过Runnable接口创建线程分为三步:


1. 将实现Runnable接口的类实例化。

2. 建立一个Thread对象,并将第一步实例化后的对象作为参数传入Thread类的构造方法。

3. 最后通过Thread类的start方法建立线程。

下面的代码演示了如何使用Runnable接口来创建线程:

[java]
package com.debug.java;

public class RunnableDemo implements Runnable {

/**

* @category 第一步:将实现Runnable接口的类实例化。

*/

public static void main(String[] args) {

RunnableDemo r = new RunnableDemo();// 第二步:实例化RunnableDemo,并将其作为Thread的参数

Thread thread1 = new Thread(r);

Thread thread2 = new Thread(r, "thread2");

thread1.start();// 第三步:开始线程

thread2.start();

}

@Override

public void run() {

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

}

}

package com.debug.java;

public class RunnableDemo implements Runnable {

/**

* @category 第一步:将实现Runnable接口的类实例化。

*/

public static void main(String[] args) {

RunnableDemo r = new RunnableDemo();// 第二步:实例化RunnableDemo,并将其作为Thread的参数

Thread thread1 = new Thread(r);

Thread thread2 = new Thread(r, "thread2");

thread1.start();// 第三步:开始线程

thread2.start();

}

@Override

public void run() {

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

}

}
输出:Thread-0

thread2

介绍完Runnable接口,再来看一下Thread类,它继承自Runnable接口。Thread类的构造方法被重载了八次,构造方法如下:
public Thread( ); public Thread(Runnable target); public Thread(String name); public Thread(Runnable target, String name); public Thread(ThreadGroup group, Runnable target); public Thread(ThreadGroup group, String name); public Thread(ThreadGroup group, Runnable target, String name); public Thread(ThreadGroup group, Runnable target, String name, long stackSize); Runnable target:

实现了Runnable接口的类的实例。要注意的是Thread类也实现了Runnable接口,因此,从Thread类继承的类的实例也可以作为target传入这个构造方法。

String name:

线程的名子。这个名子可以在建立Thread实例后通过Thread类的setName方法设置。如果不设置线程的名子,线程就使用默认的线程名:Thread-N,N是线程建立的顺序,是一个不重复的正整数。

ThreadGroup group:

当前建立的线程所属的线程组。如果不指定线程组,所有的线程都被加到一个默认的线程组中。

long stackSize:

线程栈的大小,这个值一般是CPU页面的整数倍。如x86的页面大小是4KB。在x86平台下,默认的线程栈大小是12KB。

一个普通的Java类只要从Thread类继承,就可以成为一个线程类。并可通过Thread类的start方法来执行线程代码。虽然Thread类的子类可以直接实例化,但在子类中必须要覆盖