Java——创建线程的三种方式

来源:互联网 发布:windowsce软件 编辑:程序博客网 时间:2024/05/21 17:24

创建线程的三种方式

1. 继承Thread类创建线程类

通过继承Thread类创建并启动多线程的步骤:
1. 定义该类继承Thread,并重写该类的run方法,该run()方法的方法体就代表了线程需要完成的任务。因此run()方法被称为方法执行体。
2. 创建一个Thread子类实例,即创建了线程对象。
3. 调用线程对象的start()方法来启动该进程。
下面的程序是一个示例:

package 多线程;public class MyThread extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName() + ":" + i);        }    }    public static void main(String[] args) {        MyThread my1 = new MyThread();        MyThread my2 = new MyThread();        // 启动线程        my1.start();        my2.start();    }}

可以看见Thread0与Thread1交错出现,并且是不规律的。
上面程序的getName()是进程的名称默认情况下,第一个进程是Thread0,第二个是Thread1…,getName()方法是Thread类的一个实例方法。
我们可以通过setName()来设置线程姓名
,当然setName()也是Thread的实例方法。还可以通过构造器设置线程的名称,如下:

public MyThread () {}    public MyThread (String name) {        super(name);    }

Thread中还有一个静态的方法currentThread(),该方法的作用是返回当前正在执行的线程对象。

package 多线程;public class MyThread extends Thread {    public MyThread () {}    public MyThread (String name) {        super(name);    }    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName() + ":" + i);        }    }    public static void main(String[] args) {        // 通过Thread的currentThread()方法获取当前进程        System.out.println(Thread.currentThread());        MyThread my1 = new MyThread("A");        MyThread my2 = new MyThread("B");        // 启动线程        my1.start();        my2.start();    }}

Thread.currentThread()显示的是main()方法这一条进程,当Java程序启动时,之后会启动一条主进程。

2. 实现Runnable接口创建线程类

实现Runnable接口来创建并启动多线程的步骤如下:
1. 定义一个Runnable接口的实现类,并重写该接口的run()方法,该run()方法就是该线程执行体。
2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread才是真正的线程对象。

Thread(Runnable target) 分配新的 Thread 对象
Thread(Runnable target, String name) 分配新的 Thread 对象。
3. 调用线程的start()方法来启动该线程。

下面的一个程序演示了如何启动并创建:

package 多线程;public class RunnableThreadDemo2 implements Runnable{    private int i;    @Override    public void run() {        for ( ; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " : " + i);        }    }    public static void main(String[] args) {        for (int i  = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " " + i);            if (i == 20) {                RunnableThreadDemo2 rtd = new RunnableThreadDemo2();                new Thread(rtd, "A").start();                new Thread(rtd, "B").start();            }        }    }}

可以看到运行的结果,两个子线程的i变量是连续的,也就是采用Runnable接口方式创建的多个线程是可以共享线程类实例变量。这是因为在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程可以共享一个target,所以多个线程可以共享一个线程类的实例变量。

3. 使用Callable和Future创建线程

Callable是一个有泛型的接口,Callable里定义了一个比run()方法更加强大的call()方法。
1. call()方法可以有返回值:call()方法的返回值即是Callable接口的泛型
2. call()方法可以抛出异常

Java5提供了Future接口代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口——可以作为Thread类的target。

boolean cancel(boolean mayInterruptIfRunning)试图取消对此任务的执行。如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。
boolean isCancelled()如果在任务正常完成前将其取消,则返回 true。
boolean isDone()如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。
V get()throws InterruptedException,ExecutionException如有必要,等待计算完成,然后获取其结果
V get(long timeout,TimeUnit unit)throws InterruptedException, ExecutionException,TimeoutException如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。

创建并启动有返回值的线程步骤如下:
1. 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。
2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
3. 使用FutureTask对象作为Thread的target创建并启动新线程。
4. 调用FutureTask对象的get方法来获得子线程结束后的返回值。

package 多线程;import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;public class CallableDemo {    public static void main(String[] args) {        // 创建Callable对象        CallableDemo cd = new CallableDemo();        // 使用Lambda表达式创建Callable<Integer>对象        // 使用FutureTask来包装Callable对象        // Lambda写法//        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {//            int i = 0;//            for ( ; i < 100; i++) {//                System.out.println(Thread.currentThread().getName() + " : " + i);//            }//            // call() 方法可以有返回值//            return i;//        });        FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {            @Override            public Integer call() throws Exception {                 int i = 0;                for ( ; i < 100; i++) {                    System.out.println(Thread.currentThread().getName() + " : " + i);                }                // call() 方法可以有返回值                return i;            }        });        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " : " + i);            if (i == 20) {                // 实质还是以Callable对象来启动线程的                new Thread(task, "有返回值得线程").start();            }        }        try {            // 获取线程返回值            System.out.println("子线程的返回值:" + task.get());        }        catch (Exception ex) {            ex.printStackTrace();        }    }}
原创粉丝点击