创建线程的四种方式、线程池执行Runnable、Callable任务的使用

创建线程的四种方式

    • 一、继承Thread类
    • 二、实现Runnable接口
    • 三、实现Callable接口的方式
    • 四、线程池管理,执行线程任务
      • 4.1 线程池执行Runnable任务打印10个随机数
      • 4.2 线程池执行Callable任务获取1-100的和

一、继承Thread类

  • 写一个类ThreadDemo1继承Thread线程类
  • 重写Thread类中run()方法
  • 多态的方式new出一个ThreadDemo1类的对象指向Thread类
  • 调用父类的start()方法,ThreadDemo1类中继承了父类的start()方法
class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //Thread.currentThread().getName()获取当前线程类的名字
            //线程名默认从Thread-0依次递增
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        Thread thread = new ThreadDemo1();
        thread.start();
    }
}

运行结果
创建线程的四种方式、线程池执行Runnable、Callable任务的使用_第1张图片

二、实现Runnable接口

  • 写一个类ThreadDemo2实现Runnable接口

  • 重写Runnable接口中run()方法

  • new一个ThreadDemo2的对象

  • 调用Thread类的有参构造方法,此时需要传入一个Runnable类型的参数,也就是我们的ThreadDemo2对象

    或者使用匿名子类的方式new出一个Runnable接口的子类对象

    另外一种方式是lambda的方式,这两种方式不先过多介绍

  • 调用Thread类的start()方法启动线程

class ThreadDemo2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //Thread.currentThread().getName()获取当前线程类的名字
            //线程名默认从Thread-0依次递增
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        Thread thread1 = new Thread(threadDemo2);
        thread1.start();
    }
}

运行结果
创建线程的四种方式、线程池执行Runnable、Callable任务的使用_第2张图片

三、实现Callable接口的方式

这种方式相较于实现Runnable接口的方式更为灵活,可以抛出异常,还有可以得到线程的执行结果

  • 写一个类ThreadDemo3实现Callable接口此时Callable接口有个泛型,也就是其中call()方法的返回值类型
  • 重写Callable接口中call()方法,此方法可以抛出异常
  • new一个ThreadDemo3的对象
  • 借助FutureTask类来获取线程的执行结果,调用FutureTask类的有参构造方法,此时需要传入一个Callable类型的参数

​ 或者使用匿名子类的方式new出一个Callable接口的子类对象

​ 另外一种方式是lambda的方式,这两种方式也不先过多介绍

  • 调用Thread类的有参构造方法,此时需要传入一个Runnable类型的参数,而FutureTask又实现了RunnableFuture,RunnableFuture继承了Runnable

    public class FutureTask implements RunnableFuture

  • 调用Thread类的start()方法启动线程

class ThreadDemo3 implements Callable {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum = sum + i;
        }
        System.out.println(Thread.currentThread().getName() + ":" + sum);
        return sum;
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        ThreadDemo3 threadDemo3 = new ThreadDemo3();
        FutureTask<Integer> futureTask = new FutureTask<>(threadDemo3);
        Thread thread3 = new Thread(futureTask);
        thread3.start();
        Integer sum = null;
        try {
            //get方法是阻塞方法,一个一个获取执行结果,直到结束
            sum = futureTask.get();
      //重载的方法,可以指定获取线程执行结果的时间,这个时间内获取不到结果,不会阻塞,直接获取下一个结果
          //sum = futureTask.get(1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(sum);
    }
}

运行结果
创建线程的四种方式、线程池执行Runnable、Callable任务的使用_第3张图片

四、线程池管理,执行线程任务

为了方便演示,直接用Executors调用静态方法的方式执行线程任务

4.1 线程池执行Runnable任务打印10个随机数

  • 创建一个两个线程的固定长度的线程池
  • 创建ThreadDemo4实现Runnable接口
  • 重写run()方法
  • 调用线程池的execute()方法传入一个Runnable类型的参数执行
class ThreadDemo4 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + (int) (+Math.random() * 100));
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
       //创建固定长度的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        ThreadDemo4 threadDemo4 = new ThreadDemo4();
        executorService.execute(threadDemo4);
        //关闭线程池
        executorService.shutdown();
    }
}

运行结果
创建线程的四种方式、线程池执行Runnable、Callable任务的使用_第4张图片

4.2 线程池执行Callable任务获取1-100的和

  • 创建两个线程的固定长度的线程池
  • 创建ThreadDemo5实现Callable接口
  • 重写call()方法
  • 调用线程池的submit()方法传入一个Callable类型的参数执行
  • 创建5个线程并行执行任务
  • 借助FutureTask类来获取线程的执行结果
class ThreadDemo5 implements Callable {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum = sum + i;
        }
        System.out.println(Thread.currentThread().getName() + ":" + sum);
        return sum;
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        List> tasks = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            //执行5个线程任务
            Future future = executorService.submit(new ThreadDemo5());
            tasks.add(future);
        }
        //遍历线程执行的结果
        for (Future task : tasks) {
            Integer result = null;
            try {
                result = task.get();
                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } finally {
                executorService.shutdown();
            }
        }
    }
}

运行结果
创建线程的四种方式、线程池执行Runnable、Callable任务的使用_第5张图片

你可能感兴趣的:(多线程,JAVA,线程池,java,开发语言)