双非本科准备秋招(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 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)的所有线程

kill 杀死进程

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

java

jdk提供了一些命令

jps 查看所有java进程

jstack 查看某个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() 获取线程长整型 的 id id 唯一
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("主线程结束");
      }
  }

双非本科准备秋招(14.3)—— java线程_第1张图片

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

你可能感兴趣的:(java,开发语言,求职招聘,秋招,并发编程)