Java多线程-Thread类的run方法

Java多线程-Thread类的run方法

一、背景

  • 在Java中,要使用多线程,很显然先要创建线程。
  • Java将线程抽象为Thread类。创建线程的第一步:new Thread()
  • 创建好Thread对象后,接下来,就是要启动线程,并执行线程需要做的事情:Thread对象.start();
    (1)首先会启动线程;
    (2)然后调用run方法();

二、研究Thread类的start()源码

1、源码(比较短,贴一下)

java 复制代码
public synchronized void start() {
   if (threadStatus != 0)
       throw new IllegalThreadStateException();
       
   group.add(this);

   boolean started = false;
   try {
       start0();
       started = true;
   } finally {
       try {
           if (!started) {
               group.threadStartFailed(this);
           }
       } catch (Throwable ignore) {
           
       }
   }
}

1.1 重点:start0();

  • 源码
java 复制代码
private native void start0();
  • 是一个本地方法。也很好理解,Java的线程是交由操作系统来管理的。

start0()方法是Java中的一个本地方法,也就是说它是用其他语言(通常是C或C++)实现的。

其主要逻辑是创建一个新的系统级线程,并在新线程上执行run()方法。

Java中的线程是基于操作系统的原生线程实现的,而start0()方法主要就是与操作系统进行交互,创建和启动新的系统级线程。

具体来说,start0()方法的执行逻辑一般包括以下步骤:

(1)申请系统资源创建一个新的系统级线程。

(2)将Java线程对象与新创建的系统级线程进行关联。

(3)设置线程的优先级和栈大小等线程属性。

(3)在新的系统级线程上调用Java线程对象的run()方法。

(4)如果run()方法执行结束或发生异常,清理系统级线程资源。

以上执行逻辑可能因不同的JVM实现和不同的操作系统有所不同,具体实现代码可以在JVM的源代码中找到。

三、研究Thread类的run()源码

1、源码(很关键,必须贴)

java 复制代码
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}
  • Thread类:public class Thread implements Runnable

Runnable的源码:

java 复制代码
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

既然Thread类实现了Runnable接口,就要覆写run方法。

  • target是什么?
java 复制代码
public class Thread implements Runnable {
	......
	private Runnable target;
	......
}
  • 用户可以通过这个构造方法传入target:
java 复制代码
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

四、创建线程的2种方式

通过上面的分析,要让线程执行某段逻辑的关键是,实现run方法。

有2种方式:

(1)继承Thread,并覆写run方法

(2)传入一个实现了run方法的Runnable接口的实现类

1、继承Thread,并覆写run方法

  • 示例
java 复制代码
public class PrintEvenThread extends Thread {
    @Override
    public void run() {
        // 遍历100以内的偶数
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class PrintOddThread extends Thread {
    @Override
    public void run() {
        // 遍历100以内的奇数
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
java 复制代码
public class PrintThreadTest {
    @Test
    public void testTwoPrintThread() {
        PrintEvenThread printEvenThread = new PrintEvenThread();
        PrintOddThread printOddThread = new PrintOddThread();

        printEvenThread.start();
        printOddThread.start();
    }
}
  • 还可以:匿名类的匿名对象的方式
java 复制代码
new Thread() {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}.start();

2、传入一个实现了run方法的Runnable接口的实现类

  • 示例 (匿名类的匿名对象)
java 复制代码
public class LearnCreateThreadMain3 {
    public static void main(String[] args) {
        new Thread(new PrintEven()).start();
    }
}

class PrintEven implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    }
}
  • 还可以:匿名类的匿名对象的方式
java 复制代码
new Thread(
   new Runnable() {
       @Override
       public void run() {
           for (int i = 0; i < 100; i++) {
               if (i % 2 != 0) {
                   System.out.println(
                           Thread.currentThread().getName() + ":" + i);
               }
           }
       }
   })
   .start();

五、到底执行哪个run方法?

  • 示例
java 复制代码
public class LearnCreateThreadMain4 {
    public static void main(String[] args) {
        Hi hi = new Hi();
        new Thread(hi) {
            @Override
            public void run() {
                System.out.println("hello~");
            }
        }.start();
    }
}

class Hi implements Runnable {
    @Override
    public void run() {
        System.out.println("Hi~");
    }
}
  • 看懂了"三、研究Thread类的run()源码",很容易回答:执行的是Thread子类对象的run方法。也就是输出:hello~
  • 如果子类没有覆写Thread的run()方法,那么执行的代码是:
java 复制代码
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}
  • 一旦子类覆写了,那执行的就是子类的run()方法了。
相关推荐
微学AI9 小时前
Rust语言的深度剖析:内存安全与高性能的技术实现操作
java·安全·rust
程序猿小蒜9 小时前
基于springboot的共享汽车管理系统开发与设计
java·开发语言·spring boot·后端·spring·汽车
lsp程序员0109 小时前
使用 Web Workers 提升前端性能:让 JavaScript 不再阻塞 UI
java·前端·javascript·ui
q***465210 小时前
在2023idea中如何创建SpringBoot
java·spring boot·后端
hygge99910 小时前
Spring Boot + MyBatis 整合与 MyBatis 原理全解析
java·开发语言·经验分享·spring boot·后端·mybatis
q***252110 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
WX-bisheyuange10 小时前
基于Spring Boot的民谣网站的设计与实现
java·spring boot·后端
q***146411 小时前
Spring Boot文件上传
java·spring boot·后端
WX-bisheyuange12 小时前
基于Spring Boot的民宿预定系统的设计与实现
java·spring boot·后端·毕业设计
码界奇点13 小时前
Java设计模式精讲从基础到实战的常见模式解析
java·开发语言·设计模式·java-ee·软件工程