多线程执行顺序以及run方法的调用

简介: 多线程执行顺序以及run方法的调用

首先抛出问题


在上一篇ThreadLocal使用方法中,我尝试修改了博主的代码


public class Test1 {
    static class A{
        public void get(){
            /*取得当前线程所需要的值*/
            System.out.println("A"+ti.get());
        }
    }
    static class B{
        public void get(){
            /*取得当前线程所需要的值*/
            System.out.println("B"+ti.get());
        }
    }
    /*定义一个全局变量 来存放线程需要的变量*/
    public static ThreadLocal<Integer> ti = new ThreadLocal<Integer>();
    public static void main(String[] args) {
        //创建两个线程
        for(int i=0; i<2;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Double d = Math.random()*10;
                    System.out.println(d);
                    //存入当前线程独有的值
                    ti.set(d.intValue());
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }
}

控制台打印结果



这其实是一个多线程调度问题,只涉及到了一些很简单的多线程原理(健忘的大脑,我吐了)


话不多说,我们直接来解答一下为什么会出现这个原因



先来看一个例子:


public class test {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
    }
}

输出结果:


main

这个例子说明一个问题:一个Java程序至少会有1个线程在运行,就如上面的main()方法,它是由JVM创建的一个叫main的线程调用的。控制台输出的就是这个线程的名字。


接着再看下面这段代码:


public class MyThread extends Thread{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println(Thread.currentThread().getName());
        System.out.println("运行结束!");
    }
    @Override
    public void run() {
        //super.run();
        System.out.println(Thread.currentThread().getName());
    }
}

输出结果:


main
运行结束!
Thread-0
或者是:
main
Thread-0
运行结束!

上段代码说明了两个问题:


上述代码有两个线程同时在运行:一个是JVM创建的main线程,该线程调用main函数,另一个是自己创建的MyThread线程类,名称是Thread-0,该线程调用run函数

main()函数和run()函数中的打印结果顺序不确定。这是因为在使用多线程时,代码的运行结果与代码执行顺序或调用顺序是无关的。线程是一个子任务,上面代码有两个线程,意味着两个子任务各干各的事,互不干扰,一个线程正在调用main函数,另一个线程在这个时候去调用run函数,先打印哪个函数里面的东西都不一定。虽然main()这个函数比run()函数先调用,意思是时间起点早,但是具体到函数里面的语句调用顺序就说不清楚了。


由上面的例子,我们就可以知道为什么打印结果的原因了


在main线程执行过程中,它在执行for循环时,会创建一个新线程(代号A)。它不会管这个A线程执行start()后,调用自己的run方法操作,它会立即执行第二次for循环,再创建一个新线程(代号B),在main继续执行for循环时,实际上main线程已经和A线程并行执行了




相关文章
|
3月前
|
Java 调度
Java并发基础-线程简介(状态、常用方法)
Java并发基础-线程简介(状态、常用方法)
33 0
|
24天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
1月前
|
算法 安全 Java
三种方法教你实现多线程交替打印ABC,干货满满!
本文介绍了多线程编程中的经典问题——多线程交替打印ABC。通过三种方法实现:使用`wait()`和`notify()`、`ReentrantLock`与`Condition`、以及`Semaphore`。每种方法详细讲解了实现步骤和代码示例,帮助读者理解和掌握线程间的同步与互斥,有效解决并发问题。适合不同层次的开发者学习参考。
44 11
|
25天前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
46 3
|
1月前
|
安全 Java API
|
1月前
|
Java
java开启线程的四种方法
这篇文章介绍了Java中开启线程的四种方法,包括继承Thread类、实现Runnable接口、实现Callable接口和创建线程池,每种方法都提供了代码实现和测试结果。
java开启线程的四种方法
【多线程面试题 三】、 run()和start()有什么区别?
run()方法定义线程执行的任务,而start()方法启动线程,使得run()在新的线程中异步执行;直接调用run()方法只会同步执行run()中的代码,不会创建新线程。
【多线程面试题 二】、 说说Thread类的常用方法
Thread类的常用方法包括构造方法(如Thread()、Thread(Runnable target)等)、静态方法(如currentThread()、sleep(long millis)、yield()等)和实例方法(如getId()、getName()、interrupt()、join()等),用于线程的创建、控制和管理。
|
1月前
|
Dart API C语言
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
|
1月前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
250 0