1.线程状态转换

1.线程状态及基本操作 - 图1
1.线程状态及基本操作 - 图2

状态 触发条件
WAITING 当调用wait(),join(),LockSupport.lock()方法线程会进入到WAITING状态 另外当WAITING和TIMED _WAITING状态时可以通过Object.notify(),Object.notifyAll()方法使线程转换到Runable状态
TIMED_WAITING 而同样的wait(long timeout),sleep(long),join(long),LockSupport.parkNanos(),LockSupport.parkUtil()增加了超时等待的功能,也就是调用这些方法后线程会进入TIMED_WAITING状态,当超时等待时间到达后,线程会切换到Runable的状态
BLOCKED 当线程出现资源竞争时,即等待获取锁的时候,线程会进入到BLOCKED阻塞状态,当线程获取锁时,线程进入到Runable状态。
TERMINATED 线程运行结束后,线程进入到TERMINATED状态

2.线程状态的基本操作

2.1 interrupted

2.2 join

两个好基友,一个基友先走在前面突然看见另一个基友落在后面了,这个时候他就会在原处等一等这个基友,等基友赶上来后,就两人携手并进。

如果一个线程实例A执行了threadB.join(),
其含义是:当前线程A会等待threadB线程终止后threadA才会继续执行。

2.2.1 方法关键

2.3 sleep

public static native void sleep(long millis)方法显然是Thread的静态方法,很显然它是让当前线程按照指定的时间休眠,其休眠时间的精度取决于处理器的计时器和调度器。需要注意的是如果当前线程获得了锁,sleep方法并不会失去锁。sleep方法经常拿来与Object.wait()方法进行比价,这也是面试经常被问的地方。

两者主要的区别:

  • sleep()方法是Thread的静态方法,而wait是Object实例方法
  • wait()方法必须要在同步方法或者同步块中调用,也就是必须已经获得对象锁。而sleep()方法没有这个限制可以在任何地方种使用。另外,wait()方法会释放占有的对象锁,使得该线程进入等待池中,等待下一次获取资源。而sleep()方法只是会让出CPU并不会释放掉对象锁;
  • sleep()方法在休眠时间达到后如果再次获得CPU时间片就会继续执行,而wait()方法必须等待Object.notify/Object.notifyAll通知后,才会离开等待池,并且再次获得CPU时间片才会继续执行。

3.实现多线程的方式

3.1 实现Runnable接口

  1. public class RunnableStyle implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("1111");
  5. }
  6. public static void main(String[] args) {
  7. RunnableStyle runnableStyle=new RunnableStyle();
  8. Thread thread=new Thread(runnableStyle);
  9. thread.start();
  10. }
  11. }

3.2 继承Thread类

  1. public class ThreadStyle extends Thread {
  2. @Override
  3. public void run() {
  4. System.out.println("1111");
  5. }
  6. public static void main(String[] args) {
  7. ThreadStyle t1=new ThreadStyle();
  8. Thread thread=new Thread(t1);
  9. thread.start();
  10. }
  11. }

4.两者的区别

4.1 Thread 方式创建线程

Thread 内部 run()方法

  1. /**
  2. * If this thread was constructed using a separate
  3. * <code>Runnable</code> run object, then that
  4. * <code>Runnable</code> object's <code>run</code> method is called;
  5. * otherwise, this method does nothing and returns.
  6. * <p>
  7. * Subclasses of <code>Thread</code> should override this method.
  8. *
  9. * @see #start()
  10. * @see #stop()
  11. * @see #Thread(ThreadGroup, Runnable, String)
  12. */
  13. @Override
  14. public void run() {
  15. if (target != null) {
  16. target.run();
  17. }
  18. }
  1. 以上ThreadStyle 继承Thread 类, 自定义的 run 方法**完全重写**Thread 内部中的run()方法

4.2 Runnable方式创建线程

  1. 以上RunnableStyle 实现Runnable 接口,作为Runnable 子类的形式 作为参数传入Thread 构造器中,本地方法注册后在相应平台创建好新线程后 回调 Threadrun()方法, target 为自定义Runnable子类,然后再调用子类实现的 run() 方法;

5.同时使用Thread 和Runnable 会发生什么?

  1. public static void main(String[] args) {
  2. new Thread(new Runnable() {
  3. @Override
  4. public void run() {
  5. System.out.println("我来自runnable");
  6. }
  7. } ){
  8. @Override
  9. public void run(){
  10. System.out.println("我来自Thread");
  11. }
  12. }.start();
  13. }
  1. 我来自Thread
  2. 因为 Thread 已经覆盖重写了 run 方法;

自问自答环节

1. Thread.start() 到底都干了啥,为啥能在不同的平台创建一个新的线程?

答案: java thread 类中 start()方法 在native中注册后,会到 hotspot jvm层面走流程,最终会回调 thread 中的run ()方法 执行业务流程。
从JVM层面了解线程的启动和停止