Java线程的三种创建方式

进程与线程

进程是出于执行状态中的程序,是操作系统进行资源分配和调度的独立单位。
线程可以理解为是程序的一段执行流。显然一个进程必有一个线程,该线程称为主线程。同时Java提供有方法可以创建多个线程。

创建线程

Thread类

Thread类代表线程,Java中任何线程都必须是Thread类的子类的实例。
创建线程的一般步骤:

  • 继承Thread类,重写run()方法
  • 实例化Thread子类对象
  • 调用Thread#start()方法
public class FirstThread extends Thread {
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println(this.getName()+" "+i);//可以用this直接访问到当前线程实例
        }
    }
    public static void main(String[] args) {
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);//用Thread类的静态方法访问当前线程实例

            if(i==20){
                //实例化Thread类,并调用start()方法
                new FirstThread().start();
                new FirstThread().start();
            }
        }
    }
}

Runnable接口

Thread类有一个构造函数Thread(Runnable target),可以使用Runnable接口来创建线程:

public class SecondThread implements Runnable {
    @Override
    public void run() {
        for(int i=0;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){
                SecondThread secondThread = new SecondThread();
                new Thread(secondThread,"线程1").start();
                new Thread(secondThread,"线程2").start();
            }
        }
    }
}

注意:用同一个Runnable实例创建了两个Thread,Runnable实现类中的成员对于这两个Thread是共享的。

Runnable是一个函数是接口,所以也可以使用lambda表达式:

public static void main(String[] args) {
    for(int i=0;i<100;i++){
        System.out.println(Thread.currentThread().getName()+" "+i);
        if(i==20){
            new Thread(() -> {
                for (int j=0;j<100;j++){
                    System.out.println(Thread.currentThread().getName()+" "+j);
                }
            }).start();
        }
    }
}

Callable接口

如果想在线程的执行体中抛出异常或者返回值的话就必须用到Callable接口

  • V call() throws Exception

通过实现这个方法就可以完成比run()更强大的工作。
但是Callable并不是Runnable的子类,所以不能直接传入Callable接口,需要借助一个FutureTask类来包装Callable,该类实现类Runnable接口,可以直接传入Thread构造函数。

public class ThirdThread implements Callable<String> {
    @Override
    public String call() throws Exception {
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+""+i);
        }
        return "线程执行完毕";
    }

    public static void main(String[] args) {
        //实例化FutureTask
        FutureTask<String> futureTask = new FutureTask<>(new ThirdThread());
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+""+i);
            if(i==20){
                //传入
                new Thread(futureTask).start();
            }
        }

        try {
            //主线程先阻塞,以便让副线程跑完
            Thread.currentThread().sleep(1000);
            //利用FutureRask的实例可以取出返回值
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

注意:一个FutureTask实例只可以创建一个线程,如果尝试创建多个线程只会有一个生效。

总结

直接继承Thread类的方法不常用,通常都是使用Runnable接口,如果需要返回值才考虑Callable。

猜你喜欢

转载自blog.csdn.net/qq_34935078/article/details/86071259