敞开成长之旅!这是我参加「日新计划 12 月更文应战」的第5天,点击查看活动详情

学习MOOC视频记录的笔记

回忆:

完结多线程通常有两种办法,本质上是一种办法,外在形式有多种办法
应该用start()办法发动线程而不是run()办法
中止线程实际上是一种规范,不仅需求咱们让它中止,还需求被中止的线程配合咱们
线程一生的6种状况记住图就好了

1.为什么线程通讯的办法 wait()notify()notifyAll()被界说在 Object 类里?而 sleep界说在 Thread 类里?

2.用 3 种办法完结生产者形式

3.Java SE8Java1.8JDK8 是什么联系,是同一个东西吗?

4.joinsleepwait期间线程的状况分别是什么?为什么?

ThreadObject类中的重要办法详解

1.办法概览

办法名 介绍
Thread sleep 相关 本表格的相关,指的的重载办法,也便是办法名相同,可是参数不同,例如 sleep 有多个办法,只是参数不同,实际效果大同小异
join 等候其他线程履行结束
yield 相关 抛弃现已获取到的 CPU 资源
currentThread 获取当时履行线程的引证
start,run 相关 发动线程相关
interrupt 相关 中止线程
stop(),suspend(),resume() 相关 已抛弃
Object wait/notify/notifyAll 相关 让线程暂时歇息和唤醒

2.wait, notify, notifyAll 办法详解

2.1 效果、用法

能够操控一些线程的歇息与唤醒

堵塞阶段

想让一个或多个线程去歇息一下,后续需求它或许条件成熟的时分再去唤醒它。履行 wait 办法的时分必须具有目标的Monitor 锁。调用者进入堵塞状况,不再被调度。

唤醒阶段

直到以下4种状况之一发生时,才会被唤醒

  1. 另一个线程调用这个目标的 notify() 办法且刚好被唤醒的是本线程;
  2. 另一个线程调用这个目标的 notifyAll() 办法;
  3. 过了 wait(long timeout) 规则的超时时刻,如果传入 0 便是永久等候;
  4. 线程自身调用了 interrupt() 【相似之前在sleep 的时分调用 interrupt 会抛出反常】

遇到中止

特殊状况,线程现已履行了 wait 办法,在此期间被中止了,会抛出 InterruptException 办法,而且开释掉现在现已取得的 Monitor


nofity() 会唤醒单个正在等候某目标 Monitor 目标的线程,唤醒的时分如果有多个线程在等候则会随机唤醒一个,详细的完结是交给 JVM 来说完结的。

wait()notify() 必须在 synchronized 代码块中履行,不然会抛出反常。

2.2 代码演示:4种状况

一般用法

/**
* 展现wait和notify的根本用法
* 1. 研究代码履行次序
* 2. 证明wait开释锁
*/
public class Wait {
  public static Object object = new Object();
 
  static class Thread1 extends Thread {
    @Override
    public void run() {
      // 获取同步监视器
      synchronized (object) {
        System.out.println(Thread.currentThread().getName() + "开端履行了");
        try {
          // 开释锁
          object.wait();
          // 如果在等候期间遇到了中止,需求处理反常
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        // 重新取得了锁
        System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁。");
       }
     }
   }
 
  static class Thread2 extends Thread {
 
    @Override
    public void run() {
      synchronized (object) {
        object.notify();
        // 此刻还没有开释锁,同步代码块里边一切句子履行结束之后才会开释
        System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()");
       }
     }
   }
 
  public static void main(String[] args) throws InterruptedException {
    // 确保wait()先履行,notify()后履行
    Thread1 thread1 = new Thread1();
    Thread2 thread2 = new Thread2();
    thread1.start();
    Thread.sleep(200);
    thread2.start();
   }
}

运转成果:

Thread-0开端履行了
线程Thread-1调用了notify()
线程Thread-0获取到了锁。

notifynotifyAll 展现:

/**
* 3个线程,线程1和线程2首要被堵塞,线程3唤醒它们。notify, notifyAll。
* start先履行不代表线程先发动。
*/
public class WaitNotifyAll implements Runnable {
 
  public static final Object resourceA = new Object();
 
  public static void main(String[] args) throws InterruptedException {
    Runnable r = new WaitNotifyAll();
    Thread threadA = new Thread(r, "ThreadA");
    Thread threadB = new Thread(r, "ThreadB");
 
    Thread threadC = new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (resourceA) {
          resourceA.notifyAll();
          System.out.println("ThreadC notified.");
         }
       }
     });
 
    threadA.start();
    threadB.start();
    Thread.sleep(200);
    threadC.start();
   }
 
  @Override
  public void run() {
    synchronized (resourceA) {
      System.out.println(Thread.currentThread().getName() + " got resourceA lock.");
      try {
        System.out.println(Thread.currentThread().getName() + " waits to start.");
        resourceA.wait();
        System.out.println(Thread.currentThread().getName() + "'s waiting to end.");
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
     }
   }
}
 

输出如下:

ThreadA got resourceA lock.
ThreadA waits to start.
ThreadB got resourceA lock.
ThreadB waits to start.
ThreadC notified.
ThreadB's waiting to end.
ThreadA's waiting to end.

如果运用 notify() 而不是 notifyAll()

ThreadA got resourceA lock.
ThreadA waits to start.
ThreadB got resourceA lock.
ThreadB waits to start.
ThreadC notified.
ThreadA's waiting to end.

可见只要 ThreadA 被唤醒了,而且程序永远不会结束。

如果注释掉 Thread.sleep(200);运转成果如下:

ThreadA got resourceA lock.
ThreadA waits to start.
ThreadC notified.
ThreadB got resourceA lock.
ThreadB waits to start.
ThreadA's waiting to end.

线程 C 唤醒了堵塞的线程 A ,可是之后拿到锁的线程 B 就无法取得锁了。

只开释当时 monitor 展现

履行 wait办法便是一个目标,哪一个目标履行 wait 就会开释这个目标对应的锁,而不会影响到其他的锁,锁与锁之间的行为是独立的。

/**
* 证明wait只开释当时的那把锁
*/
public class WaitNotifyReleaseOwnMonitor {
  private static volatile Object resourceA = new Object();
  private static volatile Object resourceB = new Object();
 
  public static void main(String[] args) {
 
    // 验证thread1是否还持有resourceB锁
    Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (resourceA) {
          System.out.println("ThreadA got resourceA lock.");
          synchronized (resourceB) {
            System.out.println("ThreadA got resourceB lock.");
            try {
              System.out.println("ThreadA releases resourceA lock.");
              resourceA.wait();
             } catch (InterruptedException e) {
              e.printStackTrace();
             }
           }
         }
       }
     });
 
    Thread thread2 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(1000);
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        synchronized (resourceA) {
          System.out.println("ThreadB got resourceA lock.");
          System.out.println("ThreadB tries to resourceB lock.");
          synchronized (resourceB) {
            System.out.println("ThreadB got resourceB lock.");
           }
         }
       }
     });
 
    thread1.start();
    thread2.start();
   }
}

运转成果:

ThreadA got resourceA lock.
ThreadA got resourceB lock.
ThreadA releases resourceA lock.
ThreadB got resourceA lock.
ThreadB tries to resourceB lock.

2.3 特点、性质

  • 用必须先具有 monitor 也即 synchronized
  • 只能唤醒其间一个
  • 归于 Object 类【任何目标都能够调用这些办法】
  • 相似功用的 Condition
  • 一起持有多个锁的状况

2.4 原理

  • 进口集 Entry Set
  • 等候集 Wait Set

Java并发05:趣解Thread和Object类中线程相关方法

2.5 留意点

Object.wait() 状况刚被唤醒时,通常不能马上抢到 monitor 锁,那就会从 Waiting 先进入 Blocked 状况抢到锁后再转换到 Runnable 状况(官方文档)

线程被唤醒之后一般是拿不到锁的,即进入 Block 状况;(即由 Waiting 状况到 Block 状况)

Java并发05:趣解Thread和Object类中线程相关方法

如果发生反常,能够直接跳到停止 Terminated 状况,不用再遵从途径,比方能够从 Waiting 直接到 Terminated

手写生产者顾客规划形式

为什么要运用生产者和顾客形式?

生产者和顾客解耦

Java并发05:趣解Thread和Object类中线程相关方法

生产者向行列中添加,如果加满了则进入堵塞,如果生产了(行列不空)就能够通知顾客来取了。

顾客从行列中取出,如果取完了则进入堵塞,如果取出了(行列不满)就能够通知生产者消费了。

Java并发05:趣解Thread和Object类中线程相关方法

代码:

/**
* 用wait/notify来完结生产者顾客形式
*/
public class ProducerConsumerModel {
 
  public static void main(String[] args) {
    EventStorage eventStorage = new EventStorage();
    Producer producer = new Producer(eventStorage);
    Consumer consumer = new Consumer(eventStorage);
    new Thread(producer).start();
    new Thread(consumer).start();
   }
}
 
class Producer implements Runnable {
 
  private EventStorage storage;
 
  public Producer(EventStorage storage) {
    this.storage = storage;
   }
 
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      storage.put();
     }
   }
}
 
class Consumer implements Runnable {
 
  private EventStorage storage;
 
  public Consumer(EventStorage storage) {
    this.storage = storage;
   }
 
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      storage.take();
     }
   }
}
 
/**
* 资源类
*/
class EventStorage {
  private int maxSize;
  private LinkedList<Date> storage;
 
  public EventStorage() {
    this.maxSize = 10;
    this.storage = new LinkedList<>();
   }
 
  public synchronized void put() {
    // 如果满了就等候
    while(storage.size() == maxSize) {
      try {
        wait();
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
     }
    // 不然没满就加入并通知
    storage.add(new Date());
    System.out.println("库房里有了" + storage.size() + "个产品。");
    notify();
   }
 
  public synchronized void take() {
    while(storage.size() == 0) {
      try {
        wait();
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
     }
    System.out.println("拿到了" + storage.poll() + ", 现在库房还剩余" + storage.size());
    notify();
   }
}

2.6 常见面试问题

两个线程交替打印 0~100 的奇偶数

偶线程:0
奇线程:1
偶线程:2

根本思路: synchronized 有许多的废操作。比方偶数线程先拿到锁,count++ = 1,持续履行 while 循环,偶数线程或许持续拿到锁,此刻不满足 count & 1 == 0的条件,持续循环,或许会有许多不用要的履行,直到奇数线程拿到锁并履行 count++

/**
* 两个线程交替打印0~100的奇偶数,用synchronized关键字完结
*/
public class WaitNotifyPrintOddEvenSyn {
  private static int count;
  private static final Object lock = new Object();
 
  // 新建2个线程
  // 第一个只处理偶数,第二个只处理奇数(用位运算)
  // 用synchronized来通讯
  public static void main(String[] args) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        while(count < 100) {
          synchronized (lock) {
            // 运用位运算进步功率
            if((count & 1) == 0) {
              System.out.println(Thread.currentThread().getName() + ":" + count++);
             }
           }
         }
       }
     }, "偶数").start();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        while(count < 100) {
          synchronized (lock) {
            // 运用位运算进步功率
            if((count & 1) == 1) {
              System.out.println(Thread.currentThread().getName() + ":" + count++);
             }
           }
         }
       }
     }, "奇数").start();
   }
}

更好的办法:wait()/notify() 功率更高

/**
* 两个线程交替打印0~100的奇偶数,用wait/notify完结
*/
public class WaitNotifyPrintOddEvenWait {
  private static int count = 0;
  private static final Object lock = new Object();
 
  public static void main(String[] args) {
    new Thread(new TurningRunner(), "偶数").start();
    // 让偶数线程先与奇数线程发动
    try {
      Thread.sleep(10);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    new Thread(new TurningRunner(), "奇数").start();
   }
 
  // 1. 拿到锁,咱们就打印
  // 2. 打印完,唤醒其他线程,自己就休眠
  static class TurningRunner implements Runnable {
    @Override
    public void run() {
      while(count <= 100) {
        synchronized (lock) {
          // 拿到锁就打印
          System.out.println(Thread.currentThread().getName() + ":" + count++);
          // 唤醒其他线程
          lock.notify();
          if(count <= 100) {
            try {
              // 如果使命还没结束,就让出当时的锁,并休眠
              lock.wait();
             } catch (InterruptedException e) {
              e.printStackTrace();
             }
           }
         }
       }
     }
   }
}

用程序完结两个线程交替打印 0~100 的奇偶数

手写生产者顾客规划形式

为什么 wait() 需求在同步代码块内运用,而 sleep() 不需求

为了安全,主要是让通讯变得牢靠,避免死锁或许永久等候的发生。由于如果不把 wait()notify() 都放到代码块里边的话,或许会导致先履行 notify() 再履行 wait() 。需求相互配合的操作都放到同步代码块里边了。

为什么线程通讯的办法 wait()notify()notifyAll()被界说在 Object 类里?而 sleep 界说在 Thread类里?

锁等级的操作,锁是绑定到目标中,不是绑定在线程中。Java 目标规划的是每个目标都是一把锁。

wait 办法是 Object 归于目标的,那调用 Thread.wait 会怎样样?

Thread 也是一个目标,能够做,线程退出的时分会自动履行notify,会使得整个流程被影响,不引荐这样写

怎样选择用 notify 仍是 nofityAll

考虑是需求唤醒多个线程仍是一个线程

notifyAll 之后一切的线程都会再次抢夺锁,如果某线程抢夺失败怎样办?

回到初始状况,堕入等候状况,等候持有者开释,直到拿到锁持续下一步操作

suspendresume 来堵塞线程能够吗?为什么?

由于安全问题现已被弃用了,引荐运用 waitntotify 来完结。

彩蛋:Java相关概念

JavaSEJavaEEJavaME 是什么?

SE是标准版,EE是企业版,ME是移动版,现在都是SE

JREJDKJVM 是什么联系?

JRE是Java运转时环境,是JDK的一部分;JDK是开发工具包,用于开发;JVM是JRE的一部分,JRE还有一些其他的类库

Java 版别晋级都包括了哪些东西的晋级?

类的晋级以及JVM的晋级

Java8Java1.8JDK8 是什么联系,是同一个东西吗?

最开端版别是1.1、1.2、1.3…,Java5。Java 8便是Java SE8。一般认为是同一个东西。

3.sleep办法详解

效果:我只想让线程在预期的时刻履行,其他时分不要占用 CPU 资源

不开释锁,包括 synchronizedlock ,和 wait 不同

/**
* 展现线程sleep的时分不开释synchronized的monitor,等sleep时刻到了以后,正常结束后才开释锁
*/
public class SleepDontReleaseMonitor implements Runnable {
 
  public static void main(String[] args) {
    SleepDontReleaseMonitor sleepDontReleaseMonitor = new SleepDontReleaseMonitor();
    new Thread(sleepDontReleaseMonitor).start();
    new Thread(sleepDontReleaseMonitor).start();
   }
 
  @Override
  public void run() {
    syn();
   }
 
  private synchronized void syn() {
    System.out.println("线程" + Thread.currentThread().getName() + "获取到了monitor。");
    try {
      Thread.sleep(5000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    System.out.println("线程" + Thread.currentThread().getName() + "退出了同步代码块");
   }
}

运转成果:

线程Thread-0获取到了monitor。
线程Thread-0退出了同步代码块
线程Thread-1获取到了monitor。
线程Thread-1退出了同步代码块
/**
* 演示sleep不开释lock(lock需求手动开释)
*/
public class SleepDontReleaseLock implements Runnable {
    private static final Lock lock = new ReentrantLock();
    @Override
    public void run() {
        lock.lock();
        System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁");
        try {
            Thread.sleep(5000);
            System.out.println("线程" + Thread.currentThread().getName() + "现已复苏");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        SleepDontReleaseLock sleepDontReleaseLock = new SleepDontReleaseLock();
        new Thread(sleepDontReleaseLock).start();
        new Thread(sleepDontReleaseLock).start();
    }
}

运转成果:

线程Thread-0获取到了锁
线程Thread-0现已复苏
线程Thread-1获取到了锁
线程Thread-1现已复苏

sleep 办法响应中止

  1. 抛出 InterruptedException
  2. 铲除中止状况

第二种写法(更高雅)

/**
* 每个1秒钟输出当时时刻,被中止,调查。
* Thread.sleep()
* TimeUnit.SECONDS.sleep()
*/
public class SleepInterrupted implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new SleepInterrupted());
        thread.start();
        Thread.sleep(6500);
        thread.interrupt();
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(new Date());
            try {
                // 1. 不需求转化时刻
                // TimeUnit.HOURS.sleep()
                // 2. 如果传参小于0,忽略处理
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("我被中止了!");
                e.printStackTrace();
            }
        }
    }
}

运转成果:

Mon Mar 01 20:31:54 CST 2021
Mon Mar 01 20:31:55 CST 2021
Mon Mar 01 20:31:56 CST 2021
Mon Mar 01 20:31:57 CST 2021
Mon Mar 01 20:31:58 CST 2021
Mon Mar 01 20:31:59 CST 2021
Mon Mar 01 20:32:00 CST 2021
我被中止了!
Mon Mar 01 20:32:01 CST 2021
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at threadcoreknowledge.threadobjectclasscommonmethods.SleepInterrupted.run(SleepInterrupted.java:27)
    at java.lang.Thread.run(Thread.java:748)
Mon Mar 01 20:32:02 CST 2021
Mon Mar 01 20:32:03 CST 2021

一句话总结:sleep 办法能够让线程进入 Waiting 状况,而且不占用 CPU 资源,可是不开释锁,直到规则时刻后再履行,休眠期间如果被中止,会抛出反常并铲除中止状况

wait/notify、sleep 异同(办法归于哪个目标?线程状况怎样切换?)

相同:①都会让线程进入堵塞状况;②能够响应中止

不同:①前者必须在同步办法中履行,后者不需求;②前者开释锁,后者不开释锁;③前者不指定时刻,等候被唤醒。后者指定时刻,到时刻就会被唤醒;④前者在 Object 类中,后者在 Thread 类中。

4.join办法

4.1 效果

效果:由于新的线程加入了咱们,所以咱们要等他履行完再出发

用法:main 等候 thread 履行结束,留意谁等谁

4.2 用法

4.3 三个例子

/**
* 演示join,留意句子输出次序,会变化。
*/
public class Join {
  public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(1000);
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        System.out.println(Thread.currentThread().getName() + "履行结束");
       }
     });
 
    Thread thread2 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(1000);
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        System.out.println(Thread.currentThread().getName() + "履行结束");
       }
     });
 
    thread1.start();
    thread2.start();
    System.out.println("开端等候子线程运转结束");
    thread1.join();
    thread2.join();
    // 由于join的生效,因而线程的输出句子一定在下面这条句子之前完结
    System.out.println("一切子线程履行结束");
   }
}

运转成果:

开端等候子线程运转结束
Thread-1履行结束
Thread-0履行结束
一切子线程履行结束

如果注释掉 join 句子

运转成果:

开端等候子线程运转结束
一切子线程履行结束
Thread-1履行结束
Thread-0履行结束

关于中止的状况:

/**
* 演示join期间被中止的效果
*/
public class JoinInterrupt {
  public static void main(String[] args) {
    // 获取主线程的引证
    Thread mainThread = Thread.currentThread();
 
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          // 中止主线程,此刻主线程现已给子线程让位了
          mainThread.interrupt();
          Thread.sleep(5000);
          System.out.println("Thread1 finished");
         } catch (InterruptedException e) {
          System.out.println("子线程中止");
          // e.printStackTrace();
         }
       }
     });
    // 发动子线程
    thread.start();
    System.out.println("等候子线程运转结束");
    // 子线程来插队了,实际上是主线程被中止,主线程抛出反常
    try {
      thread.join();
     } catch (InterruptedException e) {
      System.out.println(Thread.currentThread().getName() + "主线程中止了");
      // 主线程被中止的时分必须还要中止子线程,不然会出现不一致的状况
      thread.interrupt();
      // e.printStackTrace();
     }
    System.out.println("子线程现已运转结束");
   }
}
等候子线程运转结束
main主线程中止了
子线程现已运转结束
子线程中止

获取状况:

/**
* 先join再mainThread.getState(),经过debugger看线程join前后状况的比照
*/
public class JoinThreadState {
  public static void main(String[] args) throws InterruptedException {
    Thread mainThread = Thread.currentThread();
 
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(3000);
          System.out.println(mainThread.getState());
          System.out.println("Thread-0运转结束");
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
       }
     });
    thread.start();
    System.out.println("等候子线程运转结束");
    thread.join();
    System.out.println("子线程运转结束");
   }
}

运转成果:

等候子线程运转结束
WAITING
Thread-0运转结束
子线程运转结束

Java并发05:趣解Thread和Object类中线程相关方法

4.4 CountDownLatchCyclicBarrier

尽量不要直接操作底层的办法,运用更高档的封装好的类库。

4.5原理

源码

public final void join() throws InterruptedException {
  // 休眠时刻无限
  join(0);
}
public final synchronized void join(long millis)
  throws InterruptedException {
  long base = System.currentTimeMillis();
  long now = 0;
 
  if (millis < 0) {
    throw new IllegalArgumentException("timeout value is negative");
   }
 
  if (millis == 0) {
    while (isAlive()) {
      // 一向休眠
      wait(0);
     }
   } else {
    while (isAlive()) {
      long delay = millis - now;
      if (delay <= 0) {
        break;
       }
      wait(delay);
      now = System.currentTimeMillis() - base;
     }
   }
}

这里只要 wait(0),那么究竟是被谁唤醒的呢?

分析

Java并发05:趣解Thread和Object类中线程相关方法

等价

/**
* 经过解说join原理,分析出join的替代写法
*/
public class JoinPrinciple {
  public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(1000);
          System.out.println("Thread0 finished");
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
       }
     });
    thread.start();
    System.out.println("开端等候子线程运转结束");
    // thread.join();
    // 主线程拿到锁
    synchronized (thread) {
      thread.wait();
     }
    System.out.println("一切子线程履行结束");
   }
}
开端等候子线程运转结束
Thread0 finished
一切子线程履行结束

4.6常见面试问题

join 期间,线程处于哪种线程状况?

线程会处于 WAITING 的状况

5.yield办法

效果:开释我的 CPU 时刻片 –> Runnable状况,有或许下一段又被履行了

定位:JVM 不确保遵从

yieldsleep差异:是否随时或许再次被调度

6.获取当时履行线程的引证: Thread.currentThread 办法

/**
* 演示打印main,Thread-0,Thread-1
*/
public class CurrentThread implements Runnable {
 
  public static void main(String[] args) {
    new CurrentThread().run();
    new Thread(new CurrentThread()).start();
    new Thread(new CurrentThread()).start();
   }
 
  @Override
  public void run() {
    System.out.println(Thread.currentThread().getName());
   }
}