想象这样一个场景,你需要用java程序完成两个任务taskOne和taskTwo,为了结构上更加清晰明了我们一般的做法是针对这两个任务分别写一个方法taskOne()和taskTwo(),然后分别去调用这个两个方法即可完成这样的业务功能。无论是先调用taskOne()还是先调用taskTwo(),最终执行的逻辑一定是先被调用的任务执行完后再去执行后一个任务,因为这两个方法都是被同一个线程main来执行的,【单线程中肯定是按顺序执行的,程序启动时,会创建一个 非守护线程main和多个守护线程】。
案例:
package cool.datapro.concurrent; /** * @Author: bear * @DATE: 2020/08/01 23:28 */ public class TryThread { public static void main(String[] args) { // 按顺序执行 taskOne(); taskTwo(); } /** * taskOne 任务1 */ public static void taskOne(){ for (int i=1; i<=10; i++){ try { System.out.println("Task One ==>" + i); Thread.sleep(1000*1L); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * taskTwo 任务2 */ public static void taskTwo(){ for (int i=1; i<=10; i++){ try { System.out.println("Task Two ==>" + i); Thread.sleep(1000*1L); } catch (InterruptedException e) { e.printStackTrace(); } } } }
结果:
E:prosoftwarejavabinjava.exe ... Task One ==>1 Task One ==>2 Task One ==>3 Task One ==>4 Task One ==>5 Task One ==>6 Task One ==>7 Task One ==>8 Task One ==>9 Task One ==>10 Task Two ==>1 Task Two ==>2 Task Two ==>3 Task Two ==>4 Task Two ==>5 Task Two ==>6 Task Two ==>7 Task Two ==>8 Task Two ==>9 Task Two ==>10 Process finished with exit code 0
当程序运行后,我们使用Jconsole(Java 监控和管理控制台)来查看两个任务是否是被main线程来执行完的。
使用方法,程序运行后(程序还未执行完),打开cmd, 运行命令 jps 回车查看线程
C:Users11982>jps 9168 RemoteMavenServer36 18228 Launcher 13592 1500 Jps 17484 TryThread # <============这个是当前程序执行的进程 C:Users11982>jconsole 17484 C:Users11982>
此时会出现一个弹框,显示正在连接,点击 不安全的链接 即可进入到Jconsole
进入后点击线程 main 可以查看当前main线程正在执行那个任务(有延时)
上述结果说明:在一个线程中调用的方法均是依次执行(上一个执行完后再去执行下一个),无论调用几个方法,这些方法均是依托于main线程来依次执行的。
现在,业务场景变了,要求在执行taskOne()时taskTwo()也一起执行【感觉上是一起执行,实际上同一时刻还是执行了一个方法,cpu切换是有先后顺序的,只不过切换的太快,所以从意义上来理解是一起执行的】
为了完成意义上的一起同时执行,所以我们要再去创建一个线程,我们开启一个新的线程去执行taskOne(),加上应用启动时默认启动的main线程去执行taskTwo()一共两个线程
package cool.datapro.concurrent; /** * @Author: bear * @DATE: 2020/08/01 23:28 */ public class TryThread { public static void main(String[] args) { // 两个线程 Thread t1 = new Thread("TASK ONE"){ @Override public void run() { taskOne(); } }; t1.start(); // TASK ONE线程 taskTwo(); // main线程 } /** * taskOne 任务1 */ public static void taskOne(){ for (int i=1; i<=100; i++){ try { System.out.println("Task One ==>" + i); Thread.sleep(1000*1L); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * taskTwo 任务2 */ public static void taskTwo(){ for (int i=1; i<=100; i++){ try { System.out.println("Task Two ==>" + i); Thread.sleep(1000*1L); } catch (InterruptedException e) { e.printStackTrace(); } } } }
注意的是,这里为了保证在打开Jconsole时,应用程序还没执行完,我将循环扩大了100。当程序启动时,我们通过上述方式打开Jconsole,来观察线程情况
可以看到,TASK ONE 线程执行的是 taskOne()方法
main线程执行的是taskTwo()方法
程序运行结果【这里只取前11个输出来说明】
E:prosoftwarejavabinjava.exe ... Task Two ==>1 Task One ==>1 Task One ==>2 Task Two ==>2 Task One ==>3 Task Two ==>3 Task One ==>4 Task Two ==>4 Task One ==>5 Task Two ==>5 Task One ==>6 Task Two ==>6 Task One ==>7 Task Two ==>7 Task Two ==>8 Task One ==>8 Task One ==>9 Task Two ==>9 Task One ==>10 Task Two ==>10 Task Two ==>11 Task One ==>11
请先
!