天下脸皮共十分
我占八分

JUC学习笔记

线程创建的三种方式

主线程不会等待子线程结束

Java进程会等待所有线程结束

三种方式本质都是在thread构造函数中传入runnable接口的实现对象

继承Thread类并复写thread中的run方法
 package tech.ityoung.study.demo.jvm.juc;
 ​
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 ​
 @Slf4j
 public class ThreadCreattionDemo1 {
     public static void main(String[] args) throws InterruptedException {
         log.info("main thread begins");
         ThreadDemo demo = new ThreadDemo();
         demo.start();
         log.info("main thread end");
    }
 }
 ​
 @Slf4j
 class ThreadDemo extends Thread {
     @SneakyThrows
     @Override
     public void run() {
         log.info("this is subClass of Thread");
         Thread.sleep(10000);
         log.info("awake");
    }
 }
  • 匿名内部类本质上还是继承Thread类
 new Thread("sss"){
     @Override
     public void run() {
         log.info("匿名内部类");
    }
 };
image-20201221220655003
传入runnable接口
 public static void main(String[] args) {
         Thread runnable = new Thread(() -> {
             log.info("runnable");
             try {
                 Thread.sleep(10000);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
        }, "runnable");
         runnable.start();
         log.info("main thread end");
    }
image-20201221221526188
FutureTask
image-20201221222608811
  • FutureTask实现RunnableFuture,RunnableFuture继承Runnable和Future
  • FutureTask自身有实现run方法,故构造方法传入callable
 public interface RunnableFuture<V> extends Runnable, Future<V> {
     /**
      * Sets this Future to the result of its computation
      * unless it has been cancelled.
      */
     void run();
 }
 @Slf4j
 public class FutureTaskDemo {
     public static void main(String[] args) throws ExecutionException, InterruptedException {
         // 创建任务对象
         FutureTask<Integer> task3 = new FutureTask<>(() -> {
             log.debug("hello");
             return 100;
        });
         // 参数1 是任务对象; 参数2 是线程名字,推荐
         new Thread(task3, "t3").start();
         // 主线程阻塞,同步等待 task 执行完毕的结果
         Integer result = task3.get();
         log.debug("结果是:{}", result);
    }
 }

线程打断interrupt

线程打断状态

获取状态

 Thread.interrupted();
 Thread.currentThread().isInterrupted();
  • join、sleep、wait方法会以抛异常的方式提示打断,而不会改变打断标记
 @Slf4j
 public class InterruptDemo {
     public static void main(String[] args) throws InterruptedException {
         Thread t1 = new Thread(() -> {
             log.info("start sleep...");
             try {
                 TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
        }, "t1");
         t1.start();
         TimeUnit.SECONDS.sleep(1);
         t1.interrupt();
         log.info("interrupt status of ti:{}", t1.isInterrupted());
    }
 }
image-20201222224344841
  • 正常运行的程序被打断程序并不会自己停止运行
  • 通过判断打断状态可以主动停止线程
 @Slf4j
 public class InterruptDemo02 {
     public static void main(String[] args) throws InterruptedException {
         Thread t1 = new Thread(() -> {
             while (true) {
                 boolean interrupted = Thread.currentThread().isInterrupted();
                 if (interrupted) {
                     break;
                }
            }
        }, "t1");
         t1.start();
         TimeUnit.SECONDS.sleep(1);
         log.info("interrupt begin");
         t1.interrupt();
    }
 }

两阶段终止模式

image-20201222225638032

yield与sleep

sleep
  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
yield
  1. 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程
  2. 具体的实现依赖于操作系统的任务调度器
 public class YieldDemo {
     public static void main(String[] args) {
         Thread t1 = new Thread(() -> {
             int count = 0;
             for (; ; ) {
                 Thread.yield();
                 System.out.println("------------->t1:count = " + count++);
            }
        }, "t1");
         Thread t2 = new Thread(() -> {
             int count = 0;
             for (; ; ) {
                 System.out.println("--------------------------------------------->t2:count = " + count++);
            }
        }, "t2");
         t2.start();
         t1.start();
    }
 }

有时候yield并没有什么明显的实际效果

image-20201224230535361

park

  • park线程被打断不会改变isInterrupt状态
  • wait、sleep等会清空isInterrupt状态
  • interrupted()会改变interrupt状态
  • interrupt后无法重新被park,需要清除状态Thread.interrupted(),返回打断状态并清除状态
赞(0) 打赏
未经允许不得转载:Stephen Young » JUC学习笔记
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏