首页 > 编程笔记 > Java笔记 阅读:1

java创建线程的三种方法(附带实例)

在 Java 中,主要提供三种方式实现线程,分别为:
  1. 继承 java.lang.Thread 类;
  2. 实现 java.lang.Runnable 接口;
  3. 实现Callable接口。

本节将着重讲解这三种实现线程的方式。

Java继承Thread类

Thread 类是 java.lang 包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立 Thread 实例。

Thread 类中常用的两个构造方法如下:
继承 Thread 类创建一个新的线程的语法如下:
public class ThreadTest extends Thread{
}

完成线程真正功能的代码放在类的 run() 方法中,当一个类继承 Thread 类后,就可以在该类中覆盖 run() 方法,将实现该线程功能的代码写入 run() 方法中,然后调用 Thread 类中的 start() 方法执行线程,也就是调用 run() 方法。

Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在 run() 方法中。run() 方法必须使用以下语法格式:
public void run(){
}

注意,如果 start() 方法调用一个已经启动的线程,系统将抛出 IllegalThreadStateException 异常。

当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由 Java 虚拟机负责,程序员只负责启动自己的线程。

代码如下:
public static void main(String[] args){
    new ThreadTest().start();
}

【实例】创建 ThreadTest 类并继承 Thread 类,在 run() 方法中编写代码,实现循环输出 10 个数字,然后启动线程。
public class ThreadTest extends Thread{
    public void run(){
        for(int i = 1; i <= 10; i++){
            System.out.print(i + " ");
        }
    }

    public static void main(String[] args){
        ThreadTest t = new ThreadTest();
        t.start();
    }
}
运行结果如下:

1 2 3 4 5 6 7 8 9 10

start() 方法会启动线程,线程自动执行 run() 方法中的代码,就可以看到 for 循环输出的数字了。

在 main() 方法中,使线程执行就需要调用 Thread 类中的 start() 方法,start() 方法调用被覆盖的 run() 方法,如果不调用 start() 方法,线程永远都不会被动,在主方法没有调用 start() 方法之前,Thread 对象只是一个实例,而不是一个真正的线程。

Java实现Runnable接口

到目前为止,线程都是通过扩展 Thread 类来创建的,程序员如果需要继承其他类(非 Thread 类),而且还要使当前类实现多线程,那么可以通过 Runnable 接口来实现。

例如,一个扩展 JFrame 类的 GUI 程序不可能再继承 Thread 类,因为 Java 语言中不支持多继承,这时该类就需要实现 Runnable 接口使其具有使用线程的功能。

实现 Runnable 接口的语法如下:
public class Thread extends Object implements Runnable{
}
有兴趣的读者可以查询 API,从中可以发现,实质上 Thread 类实现了 Runnable 接口,其中的 run() 方法正是对 Runnable 接口中的 run() 方法的具体实现。

实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。Thread 类中有以下两个构造方法: 这两个构造方法的参数中都存在 Runnable 实例,使用以上构造方法就可以将 Runnable 实例与 Thread 实例相关联。

使用 Runnable 接口启动新的线程的步骤如下:
  1. 建立 Runnable 对象;
  2. 使用参数为 Runnable 对象的构造方法创建 Thread 实例;
  3. 调用 start() 方法启动线程。

通过 Runnable 接口创建线程时,程序员首先需要编写一个实现 Runnable 接口的类,然后实例化该类的对象,这样就建立了 Runnable 对象,接下来使用相应的构造方法创建 Thread 实例,最后使用该实例调用 Thread 类中的 start() 方法启动线程。

下图表明了实现 Runnable 接口创建线程的流程:


图 1 实现Runnable接口创建线程的流程


线程最引人注目的部分应该是与 Swing 相结合创建 GUI 程序,下面演示一个 GUI 程序,该程序实现了图标滚动的功能。

【实例】让窗体中的图标动起来。在项目中创建 SwingAndThread 类,该类继承 JFrame 类,在 SwingAndThread 类中,使用 Swing 类和线程来移动窗体中的图标。
import java.awt.Container;
import javax.swing.*;

public class SwingAndThread extends JFrame {
    int count = 0; //图标横坐标

    public SwingAndThread(){
        setBounds(300, 200, 250, 100); //绝对定位窗体大小与位置
        Container container = getContentPane(); //主容器
        container.setLayout(null); //使窗体不使用任何布局管理器

        Icon icon = new ImageIcon("src/1.gif"); //图标对象
        JLabel jl = new JLabel(icon); //显示图标的标签
        jl.setBounds(10, 10, 200, 50); //设置标签的位置与大小
        Thread t = new Thread(){
            public void run() {
                while (true) {
                    jl.setBounds(count, 10, 200, 50); //将标签的横坐标用变量表示
                    try {
                        Thread.sleep(500); //使线程休眠500毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count += 4; //使横坐标每次增加4
                    if (count >= 200) {
                        count = 10;
                    }
                }
            }
        };
        t.start(); //启动线程
        container.add(jl); //将标签添加到容器中
        setVisible(true); //使窗体可见
        setDefaultCloseOperation(EXIT_ON_CLOSE); //设置窗体的关闭方式
    }

    public static void main(String[] args) {
        new SwingAndThread();
    }
}
运行本实例,结果如下图所示:


图 2 图标向右移动

在本实例中,为了使图标具有滚动功能,需要在类的构造方法中创建 Thread 实例。在创建该实例的同时需要将 Runnable 对象作为 Thread 类构造方法的参数,然后使用内部类形式实现 run() 方法。在 run() 方法中主要循环图标的横坐标位置,当图标横坐标到达标签的最右方时,再次将图标的横坐标置于图标滚动的初始位置。

注意,启动一个新的线程,不是直接调用 Thread 子类对象的 run() 方法,而是调用 Thread 子类的 start() 方法,Thread 类的 start() 方法产生一个新的线程,该线程运行 Thread 子类的 run() 方法。

Java实现Callable接口

接下来将对实现线程的第 3 种方式进行讲解,即实现 Callable 接口。

实现 Runnable 接口和实现 Callable 接口的区别在于以下几点:
通过实现 Callable 接口实现线程的步骤如下:
下面通过一个实例演示如何通过实现 Callable 接口实现线程。代码如下:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class CallableTest {
    public static void main(String[] args) throws Exception {
        FutureTask<String> ft = new FutureTask<>(new CalThread());
        Thread thd = new Thread(ft);
        thd.start();
        System.out.println("已获取线程的返回值!返回值是\n"" + ft.get() + "'");
    }
}

class CalThread implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "请查收:已通过实现Callable接口实现线程!";
    }
}
运行结果如下:

已获取线程的返回值!返回值是
“请查收:已通过实现Callable接口实现线程!”

相关文章