自学内容网 自学内容网

Java——》创建线程的方式

推荐链接:
    总结——》【Java】
    总结——》【Mysql】
    总结——》【Redis】
    总结——》【Kafka】
    总结——》【Spring】
    总结——》【SpringBoot】
    总结——》【MyBatis、MyBatis-Plus】
    总结——》【Linux】
    总结——》【MongoDB】
    总结——》【Elasticsearch】

Java中的线程本质上就是一个Thread对象

创建线程常用方式:

  1. 继承Thread类,重写run方法
  2. 实现Runnable接口
  3. 实现Callable接口
  4. 线程池

1. 继承Thread类,重写run方法

1.1 步骤

  1. 创建Thread类的子类
  2. 重写run()方法
  3. 创建线程对象
  4. 调用start()方法,启动线程

1.2 示例

package org.example;

public class CreateThreadForThread {

    public static void main(String[] args) {
        System.out.println("main方法执行开始...");
        // Java中的线程本质上就是一个Thread对象
        Thread t1 = new MyThread();
        /*
         start()方法:
            1. 启动一个新的线程
            2. 线程不能启动多次,否则报异常
            3. 实际下真正开启线程的是CPU,当CPU空闲或分配到此任务的时候,就会创建一个新的线程,然后执行run()方法中的代码
        */
        t1.start();

        // 如果要创建多个线程,需要创建多个Thread对象
        Thread t2 = new MyThread();
        t2.start();

        Thread t3 = new MyThread();
        // 显示的调用Thread的run()方法,并没有开启新的线程
        t3.run();

        for (int i = 0; i < 100; i++) {
            System.out.println("main方法的循环..." + i);
        }
        System.out.println("main方法执行结束...");
    }
}
/**
 * 继承Thread类,重写run方法
 */
class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println("子线程执行开始....");
        for(int i = 0 ; i < 10 ; i ++){
            System.out.println("子线程的循环:"+i);
        }
        System.out.println("子线程执行结束....");
    }
}

1.3 注意

  1. 启动线程是使用start()方法而不是run()方法
  2. 调用run()方法,当前线程直接执行run()方法中的业务逻辑
  3. 线程不能启动多次
  4. 如果要创建多个线程,需要创建多个Thread对象

2. 实现Runnable接口,重写run方法

2.1 步骤

  1. 创建Runable的实现类
  2. 重写run方法
  3. 创建Runable实例对象(通过实现类来实现)
  4. 创建Thread对象,并把第3步的Runable实现作为Thread构造方法的参数
  5. 调用start方法,启动线程

2.2 示例

package org.example;

/**
 * 创建线程对象:
 * 方式1:通过Runable实现接口
 * 方式2:通过Runable匿名内部类
 * 方式3:通过lambda表达式
 */
public class CreateThreadForRunnable {
    public static void main(String[] args) {
        System.out.println("main方法执行开始...");

        MyRunnable myRunnable = new MyRunnable();
        // 方式1:创建Thread对象的时候传递了一个Runable接口实现
        Thread t1 = new Thread(myRunnable);
        // 启动线程
        t1.start();

        // 方式2:创建Thread对象的时候传递了一个Runable匿名内部类
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("匿名内部类的循环:" + i);
                }
            }
        });
        t2.start();

        // 方式3:创建Thread对象的时候传递了一个lambda表达式
        Thread t3 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("lambda的循环:" + i);
            }
        });
        t3.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main方法的循环..." + i);
        }
        System.out.println("main方法执行结束...");
    }

}

/**
 * 实现Runnable接口,重写run方法
 */
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("子线程执行开始....");
        for (int i = 0; i < 100; i++) {
            System.out.println("子线程的循环:"+i);
        }
        System.out.println("子线程执行结束....");
    }
}

2.3 优点

  1. 可以避免Java单继承带来的局限性
  2. 适合多个相同的程序代码处理同一个资源的情况,把线程同程序的代码和数据有效的分离,较好的体现了面向对象的设计思想

3. 实现Callable接口,重写call方法,配合FutureTask

前面介绍的两种创建线程的方式都是重写run()方法,而且run()方法是没有返回结果的,也就是main方法是不知道开启的线程什么时候开始执行,什么时候结束执行,也获取不到对应的返回结果。而且run()方法也不能把可能产生的异常抛出。

JDK1.5之后,推出了通过实现Callable接口的方式来创建新的线程,这种方式可以获取对应的返回结果。

3.1 步骤

  1. 创建Callable的实现类
  2. 重写call()方法
  3. 创建Callable实例对象(通过实现类来实现)
  4. 创建FutureTask实例对象,传入Callable实例对象
  5. 创建Thread实例对象,传入FutureTask实例对象作为Thread构造方法的参数
  6. 调用start方法,启动线程

3.2 示例

package org.example;

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

public class CreateThreadForCallable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main方法执行开始...");

        //1. 创建MyCallable
        Callable<Integer> myCallable = new MyCallable();
        //2. 创建FutureTask,传入Callable
        FutureTask<Integer> futureTask = new FutureTask<Integer>(myCallable);
        //3. 创建Thread线程, futureTask本质上是Runable接口的实现
        Thread t1 = new Thread(futureTask);
        //4. 启动线程,本质上是执行Runable中的run()方法,只是run()方法中调用了call()方法
        t1.start();
        //5. 做一些操作
        //6. 线程执行完成后返回的结果
        Integer count = futureTask.get();
        System.out.println("总和为:" + count);
        System.out.println("main方法执行结束...");
    }
}

/**
 * 创建Callable的实现类
 * 指定Callable的泛型,这个泛型是返回结果的类型
 */
class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("子线程执行开始....");
        int count = 0;
        for (int i = 0; i < 100; i++) {
            count += i;
        }
        System.out.println("子线程执行结束....");
        return count;
    }
}

3.3 底层实现

其实Callable接口底层的实现就是**对Runable接口实现的封装**,线程启动后执行的也是Runable接口实现中的run()方法,只是在run()方法中有调用call()方法。

3.4 Future对象

运行Callable任务可以拿到一个Future对象,表示**异步计算的结果**。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

3.5 实现Runnable接口和实现Callable接口的区别

区别实现Runnable接口实现Callable接口
版本JDK1.1之后JDK1.5之后
规定方法run()call()
返回值有,Future.get()
抛出异常不可以可以
加入线程池运行ExecutorService.execute()ExecutorService.submit()

4. 基于线程池创建线程

追其底层,其实只有一种,实现Runnble

package org.example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();

        service.execute(() -> {
            System.out.println("Hello ThreadPool");
        });
    }
}

5. 总结

package org.example;

import java.util.concurrent.*;

public class CreateThread {

    public synchronized void m1() {
        System.out.println(Thread.currentThread().getName() + " m1 ");
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello MyThread!");
        }
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("Hello MyRunnable!");
        }
    }

    // 需要指定Callable的泛型,这个泛型是返回结果的类型
    static class MyCallable implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println("Hello MyCallable");
            return "success";
        }
    }

    public static void main(String[] args) throws Exception {

        // 第1种:继承Thread类,重写run方法
        new MyThread().start();

        // 第2种:实现Runnable接口,重写run方法
        new Thread(new MyRunnable()).start();// 本质是创建Thread对象的时候传递了一个Runable接口实现

        // 第3种:匿名内部类,重写run方法
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("Hello Runnable!");
            }
        }).start();

        // 第4种:lamda表达式
        new Thread(() -> {
            System.out.println("Hello Lambda!");
        }).start();

        // 第5种:实现Callable接口,重写call方法(运行 + 返回值)
        FutureTask<String> task = new FutureTask<>(new MyCallable());// FutureTask 本质上是 Runable 接口的实现
        Thread t = new Thread(task);
        t.start();// 本质还是执行 Runable中的run方法,只是 run方法调用了call方法
        System.out.println(task.get());// 获取线程执行完成后返回的结果

        ExecutorService service = Executors.newCachedThreadPool();
        // 第6种:线程池,无返回值
        service.execute(() -> {
            System.out.println("Hello ThreadPool");
        });

        // 第7种:线程池,有返回值
        Future<String> f = service.submit(new MyCallable());
        String s = f.get();
        System.out.println(s);
        service.shutdown();

        CreateThread tt = new CreateThread();
        //1.8之前的写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                tt.m1();
            }
        }).start();

        //1.8之后的写法:默认线程名称
        new Thread(()->tt.m1()).start();
        new Thread(tt::m1).start();

        //1.8之后的写法:自定义线程名称
        new Thread(()->tt.m1(), "t1").start();
        new Thread(tt::m1, "t1").start();
    }
}

原文地址:https://blog.csdn.net/weixin_43453386/article/details/143627763

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!