Java创建线程的三种方式和线程池的使用


创建新线程
最常用的线程创建方式是使用 Runnable 接口
其次就是使用 Thread 类创建新线程
如果需要新线程有返回值则使用 CallableFuture 接口创建新线程

线程池的使用
在JDK1.5后由 Executors工厂类 可直接创建线程池
使用线程池可以合理地对系统资源进行管理


详细了解多线程↓ ↓ ↓ (写的多都没人看)


1.继承 Thread 类

实现步骤

1.新建一个 Thread 类的子类 public class Xxx extends Thread { }
2.在 Thread 类的子类中重写 run 方法,设置线程任务(开启线程要干什么)
3.在测试类中创建 Thread 类的子类对象
4.调用 Thread 类的start 方法 ,开启新的线程,自动执行run 方法

代码实例

1.创建一个 Thread 类的子类

public class NewThread extends Thread{
	//重写 run 方法,设置线程(开启线程要做什么)
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("run"+i);
        }
    }
}

2.创建 Thread 类的子类,并开启线程

【PS】是调用 start 方法开启线程,而不是调用 run 方法。调用start方法,会自动执行run方法

public class Demo {
    public static void main(String[] args) {
        NewThread nt = new NewThread();
        nt.start();
        //nt.run();//调用run方法不会开启线程
        for (int i = 0; i < 5; i++) {
            System.out.println("main"+i);
        }
    }
}

程序运行结果:

java线程池里面可以再创建线程池吗 java线程池创建多线程_java线程池里面可以再创建线程池吗

2.实现 Runnable 接口

实现步骤

1.新建 Runnable 的实现类
2.重写 Runnable 的 run 方法
3.通过 Thread 的构造方法,将 Runnable 的实现类对象传递给 Thread 类 4.通过 Thread 对象调用start方法开启线程
   因为 Runnable 接口中没有 start 方法

代码实例
1.新建Runable的实现类

public class NewThread implements Runnable{
    @Override
    public void run() {
        System.out.println("使用Runnable接口创建线程");
    }
}

2.开启新线程

public class Demo {
    public static void main(String[] args) {
    	//创建 Runable 的实现类对象
    	NewThread nt = new NewThread();
    	//创建 Thread 对象,并通过构造方法将实现类对象传递给Thread类
    	Thread t = new Thread(nt);
    	//调用 start 方法开启新线程
    	t.start();
//=======上方三行代码和下方一行代码是等价的=========
        new Thread(new NewThread()).start();//使用 匿名对象 开启线程避免繁琐

        System.out.println("main主线程");
    }
}

程序运行结果:

两条语句的打印顺序依旧是随机执行,不再截图演示

3.使用 Callable 和 Future 接口

通过此方式创建线程,可以获取新线程任务的返回值

实现步骤

1.创建 Callable<V> 接口的实现类
2.在实现类中重写 Callable 接口中的 call 方法(注意这里不是 run 方法)
3.创建 FutureTask<V> 类的对象
4.创建 Thread 类对象,将 FutureTask 对象传递到 Thread 的构造方法 5.使用 Thread 对象调用 start 方法,开启新线程

代码实例

1.新建Callable的实现类,并重写call方法

public class CallableThread implements Callable<Integer>{
	//重写call方法,编写线程任务
	//call方法的返回值类型由Callable接口的泛型决定
    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
        return i;
    }
}

2.开启新线程

public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    	//创建Callable实现类对象
        CallableThread ct = new CallableThread();
        //创建FutureTask对象,将Callable实现类对象传递到其构造方法中
        FutureTask<Integer> ft = new FutureTask<>(ct);
        //将FutureTask对象传递给Thread对象,并调用start方法开启新线程
        new Thread(ft).start();
        
        //main方法的线程任务
        int i = 0;
        for (; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
        
        //获取call方法的返回值
        Integer num = ft.get();
        System.out.println("call方法的返回值为:" + num);
    }
}

程序运行结果

java线程池里面可以再创建线程池吗 java线程池创建多线程_线程池_02


【tips】

  • 传递给Callable<V>接口的泛型是作为call方法返回值类型的
  • 获取新线程任务的返回值,可以使用FutureTaskget方法
  • get方法存在两个异常,分别是ExecutionException, InterruptedException
    需要进行处理(throws或者try/catch)
    概念

4.线程池

线程池:可以理解为存放线程的集合,需要开启新线程时,从线程池里边直接取,用完再放回线程池

线程池的使用步骤

1.使用线程池 Executors 工厂类里的 newFixedThreadPool 静态方法生产一个指定数量的线程池
2.创建一个实现类实现 Runnable 接口,重写run方法,设置线程任务
3.调用 ExecutorService 接口中的 submit 方法,传递线程任务(Runnable的实现类),开启线程
4.调用 ExecutorService 接口中的 shutdown 方法销毁线程池(不建议使用)

代码实例

public class Demo01 {
    public static void main(String[] args) {
        //开启线程池,并放入 5 个线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        int i = 1;
        //使用while循环从线程池开启 10 个线程
        //开启 10 个线程的目的是,观察线程的复用,体现线程池的价值
        while(i<=10){
            i++;
            //开启一个线程
            executorService.submit(new Thread(() -> {
                System.out.println("线程池开启线程!"+Thread.currentThread().getName());
            }));
        }
        //销毁线程池
        executorService.shutdown();
    }
}

运行结果

java线程池里面可以再创建线程池吗 java线程池创建多线程_java线程池里面可以再创建线程池吗_03


线程池的优势

减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。