线程(三)——多线程的实现方式

一.继承Thread类

  步骤
   1.定义一个类继承Teread线程类
   2.重写Thread类的run方法
   3.将要执行的程序写入run方法
   4.用线程类的start()方法启动线程

package com.xin.thread.demo01_ExtendsThread;
public class _Main {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        //如果调用start方法,程序没用输出结果
        mt.start();//用线程类的start()方法就会调用重写的run()方法
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+"线程输出:"+i);
        }
    }
}

class MyThread extends Thread {//定义一个类继承Teread线程类
    @Override
    public void run() {//重写Thread类的run方法,将要执行的程序放进run方法
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+"线程输出:"+i);
        }
    }
}

  输出结果(片段):

main线程输出:351
Thread-0线程输出:306
main线程输出:352
Thread-0线程输出:307
Thread-0线程输出:308
Thread-0线程输出:309

小结:
  查看api文档说明start()方法的作用是使该线程开始执行,Java 虚拟机调用该线程的 run 方法( 而run方法只是一个普通的方法,并不会开启一条线程)。

public class TestRunAndStart {
    public static void main(String[] args) {
        new Thread("线程一") {
            @Override
            public void run() {
                super.run();
                System.out.println(Thread.currentThread().getName());
            }
        }.start();
        new Thread("线程二") {
            @Override
            public void run() {
                super.run();
                System.out.println(Thread.currentThread().getName());
            }
        }.run();
    }
}

测试结果:

main
线程一

  注:多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动(start()方法中会判断threadStatus字段的值是否为零,如果不为零则抛出IllegalThreadStateException)。

二.实现Runnable接口

  步骤:
   1.定义一个类实现Runnable接口
   2.实现Runnable接口的run方法
   3.将要执行的程序写入run方法
   4.用线程类的start()方法启动线程

package com.xin.thread.demo02_ImplementsRunnable;
public class _Main {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());//创建线程类,将MyRunnable作为Thread中的target创建新的线程
        t.start();//用线程类的start()方法就会调用重写的run()方法
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "线程输出:" + i);
        }
    }
}

class MyRunnable implements Runnable {//定义一个类实现Runnable接口
    @Override
    //重写Thread类的run方法
    public void run() {//将要执行的程序放进run方法
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "线程输出:" + i);
        }
    }
}

  输出结果(片段):

Thread-0线程输出:625
main线程输出:730
Thread-0线程输出:626
main线程输出:731
main线程输出:732
main线程输出:733

小结:
  查看Thread类的构造方法发现public Thread(Runnable target)方法时将传入的参数赋值给Thread的target字段,而run()方法的源码如下,判断target字段是否为空(而我们通过构造函数将自定义的Runnable接口的实现传递给了target),如果不为空则调用其run方法。

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

三.实现Callable接口

  步骤:
   1.定义一个类实现Callable接口
   2.实现Callable接口的call方法
   3.将要执行的程序写入call方法中
   4.用FutureTask类来包装Callable接口实现类的对象
   5.创建Thread对象并将第4步中的FutureTask对象传递进去
   6.用线程类的start()方法启动线程
   7.可以调用第4步创建的FutureTask对象的get方法返回第3步重写的call方法的返回值。

package com.xin.thread.demo04_ImplementsCallable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class _Main_NewThread {
    public static void main(String[] args) {
        Callable c = new MyCallable();
        FutureTask<String> task = new FutureTask<String>(c);
        Thread t = new Thread(task);
        t.start();
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("主线程运行结束");
    }
}
package com.xin.thread.demo04_ImplementsCallable;

import java.util.concurrent.Callable;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "的call方法运行中");
        return Thread.currentThread().getName() + "的call方法结束";
    }
}

  输出结果:

Thread-0的call方法运行中
Thread-0的call方法结束
主线程运行结束

小结:
  实际上也是调用Thread的run方法,方法的实现是FutureTask对象的run方法。而FutureTask的run方法实际上是调用了Callable的call()方法并将call方法的返回值通过outcome字段记录起来。当通过FutureTask对象的get方法要获取call方法的返回值时会判断FutureTask对象中的状态字段,如果状态为完成则返回,如果状态为未完成则阻塞。所以只要在主线程调用FutureTask的get方法。”主线程运行结束”这段话永远在”Thread-0的call方法结束”则段话之后输出。而如果主线程没有调用FutureTask的get方法,则”主线程运行结束”这段话会在”Thread-0的call方法运行中“之前输出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值