Java多线程之创建线程有几种方式

1. 继承Thread类

一般步骤:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  2. 创建Thread子类的实例,即创建了线程对象
  3. 子类对象调用start()方法:启动线程,然后调用run()方法

代码示例

/**
 * 定义子类并重写run方法
 */
public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        // 创建子类对象,即创建了一个线程
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        // 子类对象调用start方法
        t1.start();
        t2.start();
        // 以下操作在主线程中执行
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

这种创建方式代码简单,但因为Java是单继承一旦继承了Thread类就不能继承其他类

2. 实现Runnable接口

一般步骤:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  2. 创建Runnable接口实现类的实例,并以此实例作为Thread(Runnable target)的target来创建Thread对象,该Thread对象才是真正的线程对象。
  3. 调用线程对象的start()方法来启动线程。

代码示例

/**
 * 定义Runnable接口实现类并重写run方法
 */
public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        // 创建Runnable接口实现类对象:线程任务对象
        RunnableImpl runnable = new RunnableImpl();
        //创建Thread线程对象,构造方法中传递Runnable接口实现类对象
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        // 线程对象对象调用start方法
        t1.start();
        t2.start();
    }
}

避免了单继承的局限性,可以继承其他类,多个线程可以共享同一个接口实现类的对象

3. 实现Callable接口

一般步骤:

  1. 定义Callable接口的实现类,并重写该接口的call()方法,该call()方法的方法体同样是该线程的线程执行体,需要注意的是call()方法有返回值,并且可以抛出异常
  2. 创建Callable接口实现类的对象,使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值,线程执行完成后可调用该对象的get()方法获取call()方法的返回值
  3. 使用FutureTask对象作为Thread(Runnable target)的target来创建Thread对象(因为FutureTask实现了Runnable接口)
  4. 调用线程对象的start()方法来启动线程
  5. 如果想要获取线程执行完成后的返回值可调用FutureTask对象的get()方法

代码示例

/**
 * 定义Callable接口实现类并重写call方法
 */
public class CallableImpl implements Callable<String> {

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        return Thread.currentThread().getName() + "call()方法返回值";
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建Callable接口实现类的对象
        CallableImpl callable = new CallableImpl();
        // 使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值
        FutureTask<String> task1 = new FutureTask<String>(callable);
        FutureTask<String> task2 = new FutureTask<String>(callable);
        // 创建Thread类对象并调用start方法启动线程
        new Thread(task1).start();
        new Thread(task2).start();
        // 获取call()方法的返回值,即线程运行结束后的返回值
        String result1 = task1.get();
        String result2 = task2.get();
        System.out.println(result1);
        System.out.println(result2);
    }
}

实现Callable接口方式有返回值,可以抛出异常

4. 线程池方式

  1. 定义Callable接口的实现类,并重写该接口的call()方法,
  2. 调用Executors类中的newFixedThreadPool(int n)方法创建一个线程数量为n的线程池
  3. 调用线程池对象的submit()方法执行线程,返回执行结果Future对象
  4. 调用FutureTask对象的get()方法获取线程执行完成后的返回值
  5. 调用线程池对象的shutdown()方法关闭线程池
    代码示例
public class MyStringCallable implements Callable<String[]> {

    private  String str;

    public MyStringCallable(String str ){
        this.str = str;
    }

    @Override
    public String[] call() throws Exception {
        return str.split(" +");
    }
}
public class MySumCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int x = 1; x<= 100; x++){
            sum+=x;
        }
        return sum;
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建有2个线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //提交执行字符串切割任务
        Future<String[]> futureString = executorService.submit(new MyStringCallable("aa bbb   cc    d       e"));
        System.out.println(Arrays.toString(futureString.get()));
        //提交执行求和任务
        Future<Integer> futureSum =  executorService.submit(new MySumCallable());
        System.out.println(futureSum.get());
        executorService.shutdown();
    }
}

解决了频繁创建线程的问题,降低资源消耗实现循环利用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值