『深入学习Java』(三) Java 线程基础

201 阅读2分钟

『深入学习Java』(三) Java 线程基础

什么是线程

进程:通俗讲就是正在运行的程序,会占用系统资源。 线程:属于进程,是进程中独立的执行路径。 为什么要使用多线程?在项目有很多功能需要同时运行的时候,可以提高效率。

  • 并行与并发 并行(concurrent)并发(parallel),不是同一个概念。 并发是同一时间应对多件事情的能力;而并行是同一时间多件事情的能力。 例子:你在家蹲坑,公司领导来电话了,让你处理个文件。
    • 并发。 你给领导电话挂了,过了一会儿,你蹲完了,再打电话问领导啥事儿啊。随后你去房间拿出了笔记本开始处理文件。
    • 并行。 "好的,领导。我现在就处理。"随后你从旁边掏出了笔记本,开始一边蹲坑,一边处理文件。

所以,这里的重点就是,是否在同一时间能够做多件事。

Java 中创建线程方式

实现 Thread 的 run 方法

    public void test01() {
        Thread thread = new Thread(){
            @Override
            public void run() {
                log.warn("线程运行...");
            }
        };
        thread.start();
    }

Runable 配合 Thread

     public void test02() {
        Runnable runnable = () -> log.warn("线程运行...");
        Thread thread = new Thread(runnable);
        thread.start();
    }

Callable 配合 Thread

Callable 可实现获取线程的返回值。 这里需要注意 Callable 需要被 FutureTask 封装。

     public void test03() throws ExecutionException, InterruptedException {
        Callable<String> callable = () -> "有返回值的线程...";
        FutureTask<String> futureTask = new FutureTask<>(callable);

        new Thread(futureTask).start();

        String o = futureTask.get();
        log.info(o);
    }

线程常见方法

方法名称方法描述备注
start()启动一个新线程。线程进入就绪状态,CPU时间片分配到时,可立即执行
run()线程启动后,要执行的方法体-
join()等待线程结束-
setPriority()设置线程优先级1-10 之间,提高线程被调度的概率
interrupt()中断线程线程调用wait() 、join() 、 sleep() ,抛出 InterruptedException 并且清除中断标记。
interrupted()线程是否被中断,清除线程的中断状态-
isInterrupted()线程是否被中断,不清除中断状态-
sleep()线程休眠n毫秒-
yield()向调度程序提示当前线程愿意放弃其当前对处理器的使用-
getState()获取线程状态。Java 中线程有六种状态。NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

线程状态

  • NEW尚未启动的线程。
  • RUNNABLE可运行线程,正在 Java 虚拟机中执行。 但它可能正在等待来自操作系统的其他资源,例如处理器,即CPU时间片调度。
  • BLOCKED线程阻塞,等待监视器锁。 正等待 Monitor Lock 进入同步代码块/方法 或 在调用 Object.wait 后重新进入同步代码块/方法。
  • WAITING等待线程的线程状态。
    1. 调用以下方法,使线程处于等待状态:
      • Object.wait
      • Thread.join
      • LockSupport.park
    2. 例如
      • 一个对对象调用 Object.wait() 的线程正在等待另一个线程对该对象调用 Object.notify()Object.notifyAll()
      • 已调用 Thread.join() 的线程正在等待指定线程终止
  • TIMED_WAITING具有指定等待时间的等待状态。 调用以下方法之一,线程处于定时等待状态:
    • Thread.sleep(long)
    • Object.wait(long)
    • Thread.join(long)
    • LockSupport.parkNanos
    • LockSupport.parkUntil
  • TERMINATED 已终止线程的线程状态。线程已完成执行

线程流转图

image

左侧的 NEWRUNNABLETERMINATED,是一个正常运行的线程的生命流程。即从创建到新增,再到死亡。 BLOCKEDWAITINGTIME_WAITING 则是线程处于挂起状态,但是这几个状态的具体含义是有区别的。

  • BLOCKED竞争阻塞状态。例如Thread1Thread2同时竞争锁A,Thread1竞争得了锁A,则此时Thread2处于BLOCKED状态,等待Thread1释放锁,再次竞争。
  • WAITING没有时间限制的等待状态,即不唤醒会一直处于等待态。
  • TIME_WAITING具有等待时间的等待状态。即时间一到,就会自己又运行的。 下面是一段状态流转的示例代码
public void runnableTo1() throws InterruptedException {

      Object o = new Object();

      Thread thread1 = new Thread(() -> {
          synchronized (o) {
              log.info("线程运行。");
              try {
                  o.wait();
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.info("另外的代码。");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.info("结束。");
          }
      });
      thread1.start();

      Thread thread2 = new Thread(() -> {
          synchronized (o) {
              log.info("线程运行。");
              try {
                  o.wait();
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.info("另外的代码。");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.info("结束。");
          }
      });
      thread2.start();

      Thread.sleep(500);
      Thread.State state = thread1.getState();
      System.out.println("thread1:"+state);
      Thread.State state2 = thread2.getState();
      System.out.println("thread2:"+state2);
      synchronized (o) {
          o.notifyAll();
      }

      System.out.println("thread1:"+thread1.getState());
      System.out.println("thread2:"+thread2.getState());
      Thread.sleep(1100);
      System.out.println("thread1:"+thread1.getState());
      System.out.println("thread2:"+thread2.getState());
      Thread.sleep(1000);
      System.out.println("thread1:"+thread1.getState());
      System.out.println("thread2:"+thread2.getState());
  }

运行结果

[Thread-1] INFO ThreadStatusTest - 线程运行。
[Thread-2] INFO ThreadStatusTest - 线程运行。 // 到这里,两个线程都开始运行了。
thread1:WAITING 
thread2:WAITING // 到这里,线程里调用了 wait() 方法,所以线程处于 `WAITING` 状态。
thread1:BLOCKED // o.notifyAll() 之后,thread1 未竞争到锁,所以处于`BLOCKED`
thread2:RUNNABLE // o.notifyAll() 之后,thread2 竞争到锁,所以处于`RUNNABLE`
[Thread-2] INFO ThreadStatusTest - 另外的代码。
[Thread-2] INFO ThreadStatusTest - 结束。
[Thread-1] INFO ThreadStatusTest - 另外的代码。
thread1:TIMED_WAITING // Thread.sleep(1000) 之后,线程就处于`TIMED_WAITING`
thread2:TERMINATED // thread2 执行结束了,处于最终结束态。
15:54:21.364 [Thread-1] INFO ThreadStatusTest - 结束。
thread1:TERMINATED
thread2:TERMINATED