【Java】多线程(二)多线程基础

2. 多线程基础

多线程的创建方式

  1. 继承Thread类创建线程
  2. 实现Runnable接口创建线程
  3. 使用Callable和Future创建线程
  4. 使用线程池类似Executor框架
  5. spring @Async异步注解 结合线程池

2.1 继承Thread类创建线程

public class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println("继承Thread类创建线程");
    }

    public static void main(String[] args) {
        //创建线程
        MyThread myThread = new MyThread();
        //启动线程是start()而不是run()
        myThread.start();
    }
}

2.2 实现Runnable接口创建线程

public class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println("实现Runnable接口创建线程");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
}  

2.3 使用Callable和Future创建线程

2.3.1 基本使用

Callable和Future 线程可以获取到返回结果 底层基于LockSupport

从jdk1.5开始,Java提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法,可以看作是线程的执行体,但call()方法比run()方法更强大。

call()方法可以有返回值。

call()方法可以声明抛出异常。

public class MyThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        int i = 0;
        for (; i < 100; i++){
            System.out.println(Thread.currentThread().getName()+"的循环变量i"+i);
        }
        return "线程返回值"+i;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread = new MyThread();
        FutureTask<String> futureTask= new FutureTask<>(myThread);
        new Thread(futureTask,"CallableThread").start();
        for (int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName()+"的循环变量i"+i);
        }
        String s = futureTask.get();
        System.out.println(s);
    }
}

我们可以用FutureTask来包装Callable对象, 并通过get()获取线程返回值, 注意当获取线程返回值时如果Callable线程运行速度更慢会导致当前主线程阻塞, 原理就是FutureTask底层调用了LockSupport的park()和unpark()方法

2.3.2 手写 Callable和FutureTask模式

自定义Callable接口

@FunctionalInterface
public interface MyCallable <V>{
    V call();
}

自定义FutureTask类

public class MyFutureTask<V> implements Runnable{
    MyCallable<V> myCallable;
    Object lock = new Object();
    V call;
    public MyFutureTask(MyCallable myCallable){
        this.myCallable = myCallable;
    }

    @Override
    public void run() {
        call = myCallable.call();
        synchronized (lock){
            lock.notify();
        }
    }

    
    public V get(){
        synchronized (lock){
            try {
                //wait() 方法让当前线程(调用此方法线程)进入等待状态。
                //直到其他线程调用此对象的 notify()方法或 notifyAll()方法
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return call;
    }
}

使用

public static void main(String[] args){
	MyFutureTask<Integer> task=new MyFutureTask<>((MyCallable<Integer>) () -> {
		System.out.println(Thread.currentThread().getName()+"开始执行");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 5;
	});
	new Thread(task).start();
	Integer integer = task.get();
	System.out.println(integer);
}

2.4 使用线程池类似Executor框架

public static void main(String[] args) {
	ExecutorService executorService = Executors.newCachedThreadPool();
	executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
}

2.5 spring @Async异步注解 结合线程池

2.5.1 基本使用
    @Async("taskExecutor")
    public void updateViewCount(ArticleMapper articleMapper,Article article){

        Article articleUpdate = new Article();
        articleUpdate.setViewCounts(article.getViewCounts() + 1);
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getId,article.getId());
        queryWrapper.eq(Article::getViewCounts,article.getViewCounts());
        articleMapper.update(articleUpdate,queryWrapper);
        try {
            //睡眠5秒 证明不会影响主线程的使用
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

其本质就是在不加注解的情况下,在线程池中获取一个线程去调用updateViewCount方法

2.5.2 手写 @Async异步注解

定义注解类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAsync {
    String name() default "";
}

定义切面类

@Component
@Aspect //切面 定义了通知和切点的关系
public class MyAsyncAspect {
    @Around(value = "@annotation(com.example.demo.annotation.MyAsync)")
    public void around(ProceedingJoinPoint joinPoint){
        new Thread(()-> {
            try {
                joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        },"myAsync注解线程").start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值