【Java并发编程 基础】2.线程常见8种创建方式

上篇文章主要介绍了多线程的概念,本篇文章主要描述Java中8种常见创建线程方式:

  1. 继承Thread类
  2. 实现Runable接口
  3. 实现Callable接口
  4. 线程池的方式创建
  5. 匿名内部类
  6. 使用Lambda表达式
  7. Spring中@Async注解
  8. Java8 CompletableFuture

1.通过继承Thread创建

该种方式是java最原始的方式

/**
* 继承Thread类
* @date 2018年2月22日
*/
public class TestThread extends Thread{
 
    public TestThread (String name) {
        super.setName(name);
    }
    @Override
    public void run() {
    	System.out.println("当前线程: "+Thread.currentThread().getName());
    }
}
public class Main {
 
	public static void main(String[] args) throws Exception {
        TestThread testThread = new TestThread("继承Thread线程");
        // 开启线程
        testThread.start();
    }
}

使用方式:

public class Main {
 
	public static void main(String[] args) throws Exception {
        TestThread testThread = new TestThread("继承Thread线程");
        // 开启线程
        testThread.start();
    }
}

2.通过实现Runable创建

实现Runable接口在继承Thread基础上解决了Java单继承的问题。

/**
* 实现Runnable接口
* @date 2018年2月22日
*/
public class TestRunnable implements Runnable{
    @Override
    public void run() {
    	System.out.println("当前线程: "+Thread.currentThread().getName());
    }
}

使用方式:

public class Main {
 
    public static void main(String[] args) throws Exception {
        // 实现Runnable接口
        Thread thread = new Thread(new TestRunnable(),"实现Runnable的线程");
        thread.start();
    }
}

3.Callable和Future的方式

Java提供了Callable接口,是对Runnable接口的增强版,Callable接口也提供了一个call方法可以作为线程执行体,但call方法比run方法功能更强大:
call()方法有返回值
call()方法可以声明抛出异常(在平常的run方法中只能内部捕捉)

/**
* 实现callable
* @date 2018年2月22日
*/
public class TestCallable implements Callable<Integer>{
 
    @Override
    public Integer call() throws Exception {
        System.out.println("当前线程: "+Thread.currentThread().getName());
        return 1;
    }
}

使用方式:

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// Callable和Future
        FutureTask<Integer> future = new FutureTask<>(new TestCallable());
        new Thread(future,"有返回值的线程").start();
        System.out.println("返回值:"+future.get());
    }
}

4.线程池创建线程

线程池可以解决资源合理利用问题。Java JUC包中提供了四种线程池的创建,同时还有通过线程池构造方法创建方式,本文用到的是可缓存的线程池创建方式:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池创建线程
* @date 2018年2月22日
*/
public class ExecutorTest {
 
	public static void main(String[] args) throws Exception {
        // 1.可缓存的线程 重复利用线程
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {                                                        
            final int tmp = i;                                                                
            newCachedThreadPool.execute(new Runnable() {                                      
                @Override                                                                     
                public void run() {                                                           
                    System.out.println("threadName:"+Thread.currentThread().getName()+","+tmp);
                }                                                                             
            });                                                                               
        }
	}
}

5.匿名内部类创建线程

匿名内部类是在语法糖上的不同,本质和第二种一样

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// 匿名内部类创建线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("当前线程: "+Thread.currentThread().getName());
			}
		}, "匿名内部类创建线程").start();
    }
}

6.使用Lambda表达式

使用Lambda表达式是在匿名内部类语法糖上的优化,本质和第二种一样

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// 使用Lambda表达式创建线程
		new Thread(() -> System.out.println("当前线程: "+Thread.currentThread().getName())
				, "使用Lambda表达式创建线程").start();
    }
}

7.使用@Async创建线程

在Spring框架中,提供了@Async注解来创建线程。例子:假如addUser接口耗时2秒,addMember接口耗时2秒,不使用线程的情况会4秒以上,以下就是优化接口加载速度:

@org.springframework.stereotype.Service
class Service {

    /**
     * 添加用户模拟延迟
     */
    @Async
    public Future<Integer> addUser(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("addUser方法执行完毕!");
        return new AsyncResult<Integer>(1);
    }

    /**
     * 添加会员模拟延迟
     */
    @Async
    public Future<Integer> addMember(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("addMember方法执行完毕!");
        return new AsyncResult<Integer>(1);
    }
}

测试调用:

package com.terry.async;

import com.terry.App;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@SpringBootTest(classes = App.class)
public class TestAsync {

    @Autowired
    private Service service;

    @Test
    public void testAsync(){
        long start = System.currentTimeMillis();
        Future<Integer> member = service.addMember();
        Future<Integer> user = service.addUser();

        try {
            System.out.println("结果:" + member.get() + "," + user.get());
            long end = System.currentTimeMillis();
            System.out.println("接口耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

打印输出

image-20211128153442360

8.Java8 CompletableFuture创建线程

使用Callable和Future调用get方法会导致主线程阻塞,Java8的CompletableFuture可以解决这个问题:

import java.util.concurrent.CompletableFuture;

/**
 * Java8 CompletableFuture
 * @author terry
 * @version 1.0
 * @date 2022/6/2 17:42
 */
public class TestCompletableFuture {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程 start....");
        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "线程运行完毕,结果true";
        });
        completableFuture1.thenAccept(System.out::println);
        // 没有获取到结果,主线程依然可以干活
        while (true) {
            Thread.sleep(1000);
            System.out.println("主线程执行中....");
        }
    }
}

打印结果:

主线程 start....
主线程执行中....
主线程执行中....
线程运行完毕,结果true
主线程执行中....
主线程执行中....
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

terrybg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值