多线程系列-从学会创建多线程开始

多线程

4 多线程常见场景

  • 客户端(移动端App端)开发
  • 异步发送短信/邮件
  • 执行比较耗时的代码改用多线程异步执行,提高接口的响应速度
  • 异步写入日志(日志框架底层)
  • 多线程下载

5 多线程的创建方式

5.1 继承Thread类
/**
 * @ClassName ThreadDemo
 * @Description 继承Thread
 * @Author Fclever
 * @Date 2021/12/16 11:12
 **/
public class ThreadDemo extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"running");
    }

    public static void main(String[] args) {
        // 创建线程
        ThreadDemo threadDemo = new ThreadDemo();
        // 启动线程  调用start()方法
        // 执行start方法之后,线程进入就绪状态,等待cpu的调度,分配到时间片之后,进入到运行状态
        threadDemo.start();
    }
}
5.2 实现Runnable接口
/**
 * @ClassName RunnableDemo
 * @Description 实现Runnable接口
 * @Author Fclever
 * @Date 2021/12/16 11:20
 **/
public class RunnableDemo implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"running");
    }

    public static void main(String[] args) {
        // 创建Thread类,使用实现Runnable接口的类传参
        Thread thread = new Thread(new RunnableDemo());
        // 启动线程
        thread.start();
    }
}
5.3 使用匿名内部类
/**
 * @ClassName AnonymousDemo
 * @Description 匿名内部类形式
 * @Author Fclever
 * @Date 2021/12/16 11:32
 **/
public class AnonymousDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "running");
            }
        });
        thread.start();
    }
}
5.4 使用Lambda表达式
/**
 * @ClassName LambdaDemo
 * @Description
 * @Author Fclever
 * @Date 2021/12/16 14:20
 **/
public class LambdaDemo {

    public static void main(String[] args) {
        // lambda表达式
        Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName() + "running"));
        // 启动线程
        thread.start();
    }
}
5.5 使用Callable和Future
  • 可以获取到线程的返回结果,底层使用JUC并发包的LockSupport实现
  • 主线程开辟新线程,使用Callable获取返回键结果时,主线程会等待
    • 之所以能实现这种阻塞效果,是因为FurureTask底层依赖了LockSupport
    • image-20211217102218110
    • 在调用get方法时,会将主线程阻塞,当子线程返回结果后,会重新调用方法释放主线程
/**
 * @ClassName CallableDemo
 * @Description Callable创建线程,主要特点是能够获取到线程的返回结果
 * @Author Fclever
 * @Date 2021/12/16 14:24
 **/
public class CallableDemo implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"running");
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 1;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建实现Callable接口的对象
        CallableDemo callableDemo = new CallableDemo();
        FutureTask futureTask = new FutureTask<>(callableDemo);
        // 启动线程
        Thread thread = new Thread(futureTask);
        thread.start();
        // 获取线程执行的返回值
        Object rs = futureTask.get();
        System.out.println("rs:"+rs);
        System.out.println("接收到了返回结果,主线程继续执行!");
    }
}
5.6 使用线程池(如Executor框架)
  • 核心使用复用机制来维护线程
/**
 * @ClassName ThreadPoolDemo
 * @Description 线程池Demo,使用Executors
 * @Author Fclever
 * @Date 2021/12/16 14:37
 **/
public class ThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"running");
            }
        });
    }
}
5.7 Spring @Async异步注解
  • @Async底层是通过代理实现的
  • 注意点
    • 需要在启动类上开启支持该异步注解
      • image-20211217140616879
    • @Async注解只能用于公共方法
      • 方法需要是公共以便可以代理。
    • 不可以直接在一个类中直接调用类内的异步方法
      • “自我调用不起作用”,因为它绕过了代理,直接调用底层方法
/**
 * @ClassName AsyncDemo
 * @Description Spring  @Async注解
 * @Author Fclever
 * @Date 2021/12/16 14:44
 **/
@RestController
@Slf4j
public class AsyncControllerDemo {

    @RequestMapping("/test")
    public int test() {
        log.info("<1>");
        int res = this.asyncLog();
        log.info("<3>");
        return 5;
    }


    @Async
    public int asyncLog() {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("<2>");
        return 44;
    }
}
5.8 自定义@Async异步注解
  • 自定义注解
/**
 * @ClassName FcAsync
 * @Description
 * @Author Fclever
 * @Date 2021/12/17 14:14
 **/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DiAsync {

    /**
     * 异步记录日志的方法名称
     * @return
     */
    String name() default "";
}
  • AOP
/**
 * @ClassName FcAsyncAOP
 * @Description
 * @Author Fclever
 * @Date 2021/12/17 14:56
 **/
@Aspect
@Component
@Slf4j
public class DiAsyncAOP {

    /**
     * 环绕通知
     * @param joinPoint
     */
    @Around(value = "@annotation(com.fc.multithread.diyThread.DiAsync)")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            log.info("环绕通知开始执行");
            // 给目标方法开辟线程调用
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.execute(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    joinPoint.proceed();
                }
            });
            log.info("环绕通知结束执行");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • Controller
/**
 * @ClassName DiAsyncController
 * @Description
 * @Author Fclever
 * @Date 2021/12/17 15:28
 **/
@RestController
@Slf4j
public class DiAsyncController {

    @Autowired
    private DiAsyncService diAsyncService;

    @RequestMapping("/diy")
    public String diy() {
        log.info("<1>");
        diAsyncService.test();
        log.info("<3>");
        return "22";
    }
}
  • Service
/**
 * @ClassName DiAsyncService
 * @Description
 * @Author Fclever
 * @Date 2021/12/17 15:42
 **/
@Component
@Slf4j
public class DiAsyncService {

    @DiAsync(name = "test")
    public void test() {
        try {
            log.info("目标方法执行,阻塞2s");
            Thread.sleep(2000);
            log.info("<2>");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Date 2021/12/17 15:42
**/
@Component
@Slf4j
public class DiAsyncService {

@DiAsync(name = "test")
public void test() {
    try {
        log.info("目标方法执行,阻塞2s");
        Thread.sleep(2000);
        log.info("<2>");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值