加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 钦州站长网 (https://www.0777zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

Java多线程

发布时间:2022-11-01 10:52:34 所属栏目:Unix 来源:
导读:  程序运行环境

  maven

  <dependencies>
   <dependency>
   <groupId>org.projectlombokgroupId>
   <artifactId>lombokartifactId>
   <ver
  程序运行环境
 
  maven
 
  <dependencies>
          <dependency>
              <groupId>org.projectlombokgroupId>
              <artifactId>lombokartifactId>
              <version>1.18.10version>
          dependency>
          <dependency>
              <groupId>ch.qos.logbackgroupId>
              <artifactId>logback-classicartifactId>
              <version>1.2.3version>
          dependency>
      dependencies>
  logback.xml
 
 
  <configuration >
      <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
          <encoder>
              <pattern>%date{HH:mm:ss} [%t] %logger - %m%npattern>
          encoder>
      appender>
      <logger name="com.laowa" level="debug" additivity="false">
          <appender-ref ref="STDOUT"/>
      logger>
  configuration>
  线程的创建 直接创建Thread
 
  @Slf4j
  public class Demo1 {
      public static void main(String[] args) {
          // 通过匿名内部类创建一个线程并命名为t,重写它的run方法
          Thread t = new Thread("t"){
              @Override
              public void run(){
                  log.debug("t is running");
              }
          };
          t.start();
          log.debug("main is running");
      }
  }
  使用Runnable配合Thread
 
  将线程(Thread)与可执行任务(Runnable)解耦,提高灵活性
 
  @Slf4j
  public class Demo2 {
      public static void main(String[] args) {
  //        Runnable runnable = new Runnable() {
  //            @Override
  //            public void run() {
  //                log.debug("running");
  //            }
  //        };
  //        Thread t = new Thread(runnable,"t");
          // 使用lambda表达式简化
          Thread t = new Thread(()->{
              log.debug("running");
          },"t");
          t.start();
          log.debug("main is running");
      }
  }
  Thread和Runnable的关系
 
  FutureTask配合Thread
 
  FutureTask是Runnable子类(FutureRunnable)的子类可以接收Callable类型的参数unix线程切换,是对Runnable的扩展,可以用来获取任务的执行结果
 
  @Slf4j
  public class Demo3 {
      static int a = 1;
      static int b = 2;
      public static void main(String[] args) throws ExecutionException, InterruptedException {
          // Callable也是函数式接口,可以用lambda表达式简化
          FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
              @Override
              public Integer call() throws Exception {
                  log.debug("thread running");
                  // 演示方便,此处应处理线程安全
                  return a+b;
              }
          });
          Thread t = new Thread(task,"t");
          t.start();
          log.debug("结果:{}",task.get());
      }
  }
  查看进程与线程的运行 windows linux Java 线程运行原理 栈与栈帧
 
  Java方法的运行是基于JVM栈的,每个线程启动时,JVM就会给它分配一块栈内存
 
  线程上下文切换
 
  因为一些原因导致cpu不再执行当前线程没转而执行另一个线程,就会发生线程上下文切换
 
  当发生上下文切换时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java中对应的概念就是程序计数器,它的作用时记住下一条jvm执行地址
 
  thread常见方法
 
  start():
 
  启动一个新线程,在新的线程运行run方法中的代码;start只是让线程进入就绪,里面代码不一定立刻运行(CPU的时间片还没有分到),每个线程的start只能调用一次,调用多次会抛出IllegalThreadStateException
 
  run():
 
  新的线程启动后会调用这个方法,如果在构造Thread对象传递了Runnable参数,则线程启动后会调用Runnable中的run方法,某人不执行任何操作,可以创建子类来覆盖默认行为
 
  join()、join(long n)
 
  父线程等待该线程运行结束,可以传入参数指定最多等待n毫秒
 
  getId():
 
  获取线程长整型的id,这个id是唯一的
 
  getName()、setName(String name):
 
  线程名的getter和setter方法,线程名会在日志中打印,可以清楚的分辨出不同的线程
 
  getPriority()、setPriority(int newPriority):
 
  线程优先级的getter和setter方法,Java中规定线程优先级是1~10的整数,较大的优先级能提高该线程被CPU调度的几率
 
  getState():
 
  获取线程状态,Java中线程的状态时用6个Enum表示,分别为NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
 
  isInterrupted()、interruputed():
 
  判断线程是否被打断,isInterruted非静态方法且不会清除打断标记,interrupted是静态方法且会清除打断标记
 
  isAlive():
 
  线程是否存活,即是否还没有运行完毕
 
  interrupt():
 
  打断线程,如果被打断的线程正在sleep、wait、join会导致被打断的线程抛出InterruptedException,并清除打断标记;如果正在运行的线程被打断,则会设置打断标记;park的线程被打断,也会设置打断标记
 
  currentThread():
 
  静态方法,获取当前执行该方法的线程
 
  sleep(long millis):
 
  静态方法,让当前执行的线程休眠n毫秒,让出cpu的时间片,但不会释放对象锁调用sleep会让当前线程从Running进入Timed Wating状态(阻塞态)其他线程可以使用interrupt方法打断正在休眠的线程,这时sleep方法会抛出InterruptedException睡眠结束后的此案成未必会立刻得到执行,需要等待时间片分到这个线程才能执行建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性如TimeUnit.SECONDES.sleep(1)和Thread.sleep(1000)
 
  yield():
 
  静态方法,提示线程调度器让出线程对CPU的使用,主要用于测试和调式调用yield会让当前线程从Running进入Runnable状态(就绪态),然后调度其他同优先级的线程,如果这是没有同优先级的线程,那么不能保证让当前线程的暂停效果具体的实现依赖于操作系统的任务调调度器 start() vs run()
 
  run方法仅仅是一个普通的方法调用,它并不启动一个线程,而且也可以随意调用;但start的方法会启动一个新的线程,它只能调用一次
 
  @Slf4j
  public class Demo4 {
      public static void main(String[] args) {
          Thread t = new Thread(()->{
              log.debug("thread running");
          },"t");
          t.run();
          t.start();
      }
  }
  sleep和yield的区别
 
  sleep后线程进入阻塞态,而yield后线程进入就绪态;sleep结束之前线程不会被分到时间片,而yield在没有其他线程用时间片时,他还是会分到时间片
 
  join的应用
 
  join用作处理线程间的同步问题,当某个线程需要在另一个线程的处理结果基础上执行操作,就需要两个线程同步执行
 
  同步的概念
 
  @Slf4j
  public class Demo {
      static int num =0;
      public static void main(String[] args) throws InterruptedException {
          Thread t = new Thread("t"){
              @Override
              public void run(){
                  num++;
              }
          };
          Thread t2 = new Thread(()->{
              try {
                  t.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              num*=10;
          },"t2");
          t.start();
          t2.start();
          
          t2.join();
          log.debug("结果为{}",num);
      }
  }
  不推荐的方法
 
  这些方法已过时,容易破坏同步代码块,造成线程死锁
 
  stop()停止线程suspend()挂起线程resume()恢复线程 守护线程
 
  Java进程只有在所有线程结束之后才会结束,如果还有线程在运行,即使主线程结束,Java进程也不会结束,如以下代码
 
  @Slf4j
  public class Demo {
      public static void main(String[] args){
          Thread t = new Thread(()->{
              while (true){
              }
          },"t");
          t.start();
      }
  }
  有一种特殊的线程叫守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束,通过setDaemon(true)来指定为守护线程
 
  线程状态 操作系统层面
 
  JavaAPI层面

  多线程应用(统筹-烧水泡茶)
 
  假设洗水壶1s,烧开水15s,洗茶杯1s,泡茶1s;对这些动作做一个规划
 
  @Slf4j
  public class Demo {
      public static void main(String[] args) throws InterruptedException {
          long start = System.currentTimeMillis();
          washTeapot();
          Thread t = new Thread(()->{
              try {
                  heatUpWater();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          },"t");
          t.start();
          washCup();
          t.join();
          makeTea();
          long end = System.currentTimeMillis();
          log.debug("用时{}s",(end-start)/1000);
      }
      private static void washTeapot() throws InterruptedException {
          TimeUnit.SECONDS.sleep(1);
      }
      private static void heatUpWater() throws InterruptedException {
          TimeUnit.SECONDS.sleep(15);
      }
      private static void washCup() throws InterruptedException{
          TimeUnit.SECONDS.sleep(1);
      }
      private static void makeTea() throws InterruptedException{
          TimeUnit.SECONDS.sleep(1);
      }
  }
 
 

(编辑:PHP编程网 - 钦州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章