双非本科准备秋招(14.3)—— java线程

创建和运行线程

1、使用Thread

  @Slf4j(topic = "c.Test1")
  public class Test1 {
      public static void main(String[] args) {
          Thread t = new Thread("t1") {
              @Override
              public void run() {
                  log.debug("running");
              }
          };
          t.start();
  ​
          log.debug("running");
      }
  }
09:22:32 [main] c.Test1 - running

09:22:32 [Thread-0] c.Test1 - running

Process finished with exit code 0

2、Runnable配合Thread

好处是任务与线程分离,推荐这样写。

 @Slf4j(topic = "c.Test1")
  public class Test1 {
      public static void main(String[] args) {
          Runnable runnable = new Runnable() {
              @Override
              public void run() {
                  log.debug("running");
              }
          };
  ​
          Thread t = new Thread(runnable, "t2");
  ​
          t.start();
  ​
          log.debug("running");
      }
  }
09:26:17 [main] c.Test1 - running

09:26:17 [t2] c.Test1 - running

可以用lambda表达式简化

  @Slf4j(topic = "c.Test1")
  public class Test1 {
      public static void main(String[] args) {
          Thread t = new Thread(() -> log.debug("running"), "t2");
  ​
          t.start();
  ​
          log.debug("running");
      }
  }

3、获取任务执行结果——FutureTask

接收一个Callable,可以看到Callable是一个函数式接口,与Runnable的区别是Callable有返回值。

  

接收一个实现Callable接口的对象,我直接用lambda表达式

  @Slf4j(topic = "c.Test1")
  public class Test1 {
      public static void main(String[] args) throws ExecutionException, InterruptedException {
          FutureTask<Integer> ft = new FutureTask<>(() -> {
              log.debug("running");
              return 100;
          });
  ​
          Thread t = new Thread(ft, "t3");
  ​
          t.start();
  ​
          //阻塞
          Integer n = ft.get();
          log.debug("running,{}", n);
      }
  }
09:37:59 [t3] c.Test1 - running

09:37:59 [main] c.Test1 - running,100

FutureTask的get方法会一直等待FutureTask结束返回结果,所以FutureTask没结束,它就会被阻塞。

查看线程进程方法

Windos

1、任务管理器:ctrl+shift+esc

2、控制台:

tasklist | findstr java 过滤查看java的进程

taskkill杀死进程 /F强制杀死 /PID+进程编号,例如:taskkill /F /PID 23847

Linux

ps -fe 查看所有进程

ps -fT -p <PID> 查看某个进程(PID)的所有线程

kill 杀死进程

top -H -p <PID> 查看某个进程的所有线程

java

jdk提供了一些命令

jps 查看所有java进程

jstack <PID> 查看某个java进程的所有线程状态

jconsole 图形化界面,查看java进程中线程的运行情况。

线程运行原理

​ 学完JVM之后就很清楚了,每个线程的创建都会伴随一个虚拟机栈的创建,线程中的一个个方法就是一个个栈帧,每次运行一个方法就会进入虚拟机栈,方法结束后会出栈。

​ 上下文切换(Thread Context Switch)

cpu不再执行当前线程,转而执行另一个线程,这就是上下文切换。

可能的原因:cpu时间片用完了,垃圾回收,更高优先级的线程可能运行;线程自己调用了sleep、yield、wait、join、park、synchronized、lock等方法。

上下文切换时,需要保存当前线程的状态,jvm的每个线程都有自己的程序计数器(PCR),用来记录下一条jvm指令的地址。

常见方法

方法名功能说明注意
start()启动一个新线 程,在新的线程 运行 run 方法 中的代码start 方法只是让线程进入就绪,里面代码不一定立刻 运行(CPU 的时间片还没分给它)。每个线程对象的 start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException
run()新线程启动后会 调用的方法如果在构造 Thread 对象时传递了 Runnable 参数,则 线程启动后会调用 Runnable 中的 run 方法,否则默 认不执行任何操作。但可以创建 Thread 的子类对象, 来覆盖默认行为
join()等待线程运行结 束
join(long n)等待线程运行结 束,最多等待 n 毫秒
getId()获取线程长整型 的 idid 唯一
getName()获取线程名
setName(String)修改线程名
getPriority()获取线程优先级
setPriority(int)修改线程优先级java中规定线程优先级是1~10 的整数,较大的优先级 能提高该线程被 CPU 调度的机率
getState()获取线程状态Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
isInterrupted()判断是否被打 断,不会清除 打断标记
isAlive()线程是否存活 (还没有运行完 毕)
interrupt()打断线程如果被打断线程正在 sleep,wait,join 会导致被打断 的线程抛出 InterruptedException,并清除打断标记 ;如果打断的正在运行的线程,则会设置打断标记 ;park 的线程被打断,也会设置打断标记
interrupted()判断当前线程是 否被打断会清除 打断标记
currentThread()获取当前正在执 行的线程
sleep(long n)让当前执行的线 程休眠n毫秒, 休眠时让出 cpu 的时间片给其它 线程
yield()提示线程调度器 让出当前线程对 CPU的使用

守护线程

        默认情况下,java进程会等待所有线程结束,才会结束。但是守护线程特殊,只要其他非守护线程结束了,那么就会强制结束守护进程。

        举例:通过setDaemon(true)可以设置线程为守护线程,可以看到守护线程中的“运行结束”根本没打印出来,就被停止了。

  package com.smy.n2;
  ​
  import lombok.extern.slf4j.Slf4j;
  ​
  import static java.lang.Thread.sleep;
  ​
  @Slf4j(topic = "c.daemen")
  public class Daemon {
      public static void main(String[] args) throws InterruptedException {
          Thread t = new Thread(() -> {
              log.debug("开始运行");
              try {
                  sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("运行结束");
          });
  ​
          t.setDaemon(true);
          t.start();
  ​
          sleep(200);
          log.debug("主线程结束");
      }
  }

应用场景:垃圾回收器就是一种典型的守护线程,java程序停止了,垃圾回收器也会跟着停止。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值