带妹进大厂面试题(二):实现多线程的方式

实现多线程的方式

使用实现多线程有四种方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口,重写call()方法。然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread
  4. (推荐)自定义线程池。这样线程的配置自己也能把控。

一、继承 Thread 类

public class Main {
    public static void main(String[] args) {
        //线程的调用入口,调用start方法
        new MyThread().start();
    }
}

class MyThread extends Thread {
    //重写run方法
    @Override
    public void run() {
       //实现自己的业务逻辑
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
    }
}

优点:简单,且只需要实现父类的run方法即可(start方法中含有run方法,会创建一个新的线程,而run是执行当前线程)。

缺点:Java的单继承,如果对象已经继承了其他的类则不能使用该方法。且不能获取线程的返回值

二、实现Runnable 接口

public class Main {
    public static void main(String[] args) {
     // 将Runnable实现类作为Thread的构造参数传递到Thread类中,然后启动Thread类
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
    }
}

优点:简单,实现Runnable接口必须实现run方法。

缺点:创建一个线程就必须创建一个Runnable的实现类,且不能获取线程的返回值。

三、 实现Callable接口,重写call()方法。然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread

public class Main {
    public static void main(String[] args) throws Exception {
     // 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();

        // get方法会阻塞调用的线程
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
    }
}


class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");

        int sum = 0;
        for (int i = 0; i <= 100000; i++) {
            sum += i;
        }
        Thread.sleep(5000);

        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
        return sum;
    }
}

优点:可以获取多线程的返回值。

缺点:每个多线程都需要创建一个Callable的实现类

四、自定义线程池

public class Main {
    public static void main(String[] args) throws Exception {
     // 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();

        // get方法会阻塞调用的线程
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
    }
}


class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");

        int sum = 0;
        for (int i = 0; i <= 100000; i++) {
            sum += i;
        }
        Thread.sleep(5000);

        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
        return sum;
    }
}

优点:可以根据实际情况创建线程数量,且只需要创建一个线程池即可,也能够通过Callable和Future接口得到线程的返回值,程序的执行时间与线程的数量紧密相关。

缺点:需要手动销毁该线程池(调用shutdown方法)。

猜你喜欢

转载自blog.csdn.net/y1120944224/article/details/128360963