SpringBoot学习总结(四)-多线程与线程池

105 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看详情

在漫漫编码长路上学会简单的CURD操作不足以应付路上全部关卡与荆棘,当同步方法调用链过长,当计算量无法满足短时间内返回结果,当外部调用不能即时返回结果时我们需要怎么才能迈过这道坎,怎么能在不影响其他同步方法执行又能执行其他逻辑,多线程给我们解决了这个问题;

基础概念

在了解多线程之前先来了解下进程,进程是一个正在执行的程序,程序执行是按照一个固定顺序执行,而线程是进程中的实际运作单位,也是程序中可以最小的调度单位,多线程就是在一个进程中开启多个线程同时运作,可以在同一时间完成更多的任务,可以提高资源利用率,同步完成多项任务;

多线程技术同样有优点与缺点,它提高了资源利用率,提高程序运行效率,但是使用不当创建大量线程时会导致操作系统需要在线程之间切换影响服务器性能,多线程操作共享资源时容易造成堵塞,造成死锁;

线程的生命周期:从新建线程对象(new)到就绪状态(start)再到运行状态(Runing)或者通过wait,sleep等方法的等待,阻塞,睡眠状态到最后的终止状态是线程的五种基本状态;

java 创建多线程

在java中如何创建多线程,Java提供了三种实现方式: 1:集成Thread类,通过继承该类重写该类中的run方法,可以实现将逻辑代码存储在该方法中执行线程,调用start方法进行;

public class Test1 {
   public static void main(String[] args) {
       Test test = new Test();
       test.start();
   }
}
class Test extends Thread {
   @Override
   public void run() {
       System.out.println("多线程执行");
   }
}

2:实现Runnable接口实现多线程,重写接口中的run方法,编写逻辑代码,通过Thread类对象建立线程对象,通过Runnable接口的子类对象传参给Thread类的构造函数,调用Thread类的start方法执行;new Thread(implements Runnable类的对象).start;

public class Test1  {
  public static void main(String[] args) {
     new Thread(new Test()).start();
  }
}
class Test implements Runnable{
  @Override
  public void run() {
      System.out.println("多线程执行");
  }
}

3:实现Callable接口实现多线程,该方法重写call方法,并且可以有返回值,抛出异常,通过Future对象获取异步结果,这些是Runnable不能实现的;


public class Test1  {
  public static void main(String[] args) {
      Test test = new Test();
      FutureTask futureTask = new FutureTask<>(test);
      new Thread(futureTask).start();
      List<Integer> lists = null;
      try {
          lists = (List<Integer>)futureTask.get();
      } catch (InterruptedException e) {
          e.printStackTrace();
      } catch (ExecutionException e) {
          e.printStackTrace();
      }
      System.out.println(lists);
  }
}


class Test implements Callable {
  @Override
  public List<Integer> call() throws Exception {
      return Arrays.asList(1, 1);
  }
}
其他方法

Thread提供了一些方法可以对多线程更多样的操作:
Thread.currentThread()可以获取当前正在执行的线程对象的引用; set/getName()设置或获取线程名称; set/getPriority()设置或获取线程的优先级; sleep()线程休眠指定时间; join()当有线程执行时该方法可以用来临时加入线程执行,等join的线程执行完毕在继续执行原有线程; yield()线程让步,暂停当前线程,重新执行;

共享资源操作

当多线程并发操作对共享数据资源进行操作时,容易导致数据发生冲突,需要加入同步锁来避免数据操作未完成之前被其他线程操作;可以使用sunchronized关键字进行修饰,同步代码块或同步方法或者使用lock获取锁,当资源竞争激烈时lock性能相对优于synchronized,当线程睡眠时不会释放锁从而造成死锁情况,可以通过同意获取锁的顺序或者轮询锁来防止死锁产生;

线程池

当项目中大量使用多线程技术时会造成线程创建与销毁比较频繁,造成资源浪费影响性能,可以通过线程池技术来缓解该情况,提前创建多个线程,使用时从线程池获取,使用完毕放回线程池,提高响应速度降低资源消耗,更方便管理线程;

可以通过Executors类来创建线程池,可以创建可根据设定自动创建新线程的线程池,可以重复使用固定数量线程池,创建只有一个线程的线程池,延迟或定时执行的线程池;

  public static void main(String[] args) {
      //创建两个线程池
      ExecutorService pool = Executors.newFixedThreadPool(2);
      pool.submit(new Test());
      pool.submit(new Test());
      pool.submit(new Test());
      pool.shutdown();
  }
}

class Test implements Runnable{
  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName()+"执行线程");
  }
@Async

在spring boot中可以使用@Async注解来异步执行;

1:在启动类添加@EnableAsync注解开启spring boot对异步方法的的支持;

2:定义线程池;

3:使用@Async注解标注需要异步执行的方法,可以在该注解中标注使用自定义线程池;

该注解标注的方法为异步方法,当标注在类上代表该类方法都是异步方法,同类调用异步失效;