乐趣区

关于java:并发王者课-青铜-1兵分三路-从创建线程开始

从本文开始,我将基于王者中的段位和场景,从 青铜 黄金 铂金 砖石 星耀 王者 ,不同的段位对应不同的难易水平,由浅入深逐渐介绍 JAVA 中的并发编程,并在每 周二、四、六 继续更新。

在文章的常识体系方面,次要以实际为主,并在实践中交叉理论知识的解说,而本文将从最简略的线程创立开始。

一、一个游戏场景

在本局游戏中,将有 3 位玩家出场,他们别离是哪吒、苏烈和安其拉。依据玩家不同的角色定位,在王者峡谷中,他们会有不同的游戏路线:

  • 作为兵士的哪吒将走上路的反抗路线;
  • 法师安其拉则去镇守中路;
  • 战坦苏烈则决定去下路。

二、代码实现

不言而喻,你曾经发现这几个玩家必定不是单线程。接下来,咱们将通过简略的多线程模拟出他们的路线。当然,实在的游戏引擎中绝不会是几个简略的线程,状况会简单很多。

public static void main(String[] args) {Thread neZhaPlayer = new Thread() {public void run() {System.out.println("我是哪吒,我去上路");
            }
        };
        Thread anQiLaPlayer = new Thread() {public void run() {System.out.println("我是安其拉,我去中路");
            }
        };
        Thread suLiePlayer = new Thread() {public void run() {System.out.println("我是苏烈,我去下路");
            }
        };
        neZhaPlayer.start();
        anQiLaPlayer.start();
        suLiePlayer.start();}

代码的运行后果:

我是哪吒,我去上路
我是苏烈,我去下路
我是安其拉,我去中路

Process finished with exit code 0

以上,就是游戏中简略的代码片段。咱们创立了 3 个线程示意 3 个玩家,并通过 run() 办法实现他们的路线动作,随后通过 start() 启动线程。它足够简略,然而这里有 3 个知识点须要你注意。

1. 创立线程

Thread neZhaPlayer = new Thread();

2. 执行代码片段

public void run() {System.out.println("我是哪吒,我去上路");
}

3. 启动线程

neZhaPlayer.start();

对于咱们来说,创立线程并不是咱们的指标,咱们的指标是运行咱们冀望的代码(比方玩家的游戏路线或某个动作),而线程只是咱们实现这一指标的形式。因而,在编写多线程代码时,运行指定的代码片段无疑是极其重要的。在 Java 中,咱们次要有 2 种形式来指定:

  • 继承 Thread 并重写 run 办法;
  • 实现 Runnable 接口并将其传递给 Thread 的结构器。

三、线程创立的两种形式

1. 继承 Thread 创立线程

在下面的示例代码中,咱们所应用的正是这种形式,只不过是匿名实现,你也能够通过显示继承:

public class NeZhaPlayer extends Thread {public void run() {System.out.println("我是哪吒,我去上路");
    }
}

此外,在 Java 以及更高的 JDK 版本中,你还能够通过 lambda 表达式简化代码:

Thread anQiLaPlayer = new Thread(() -> System.out.println("我是哪吒,我去上路"));

2. 实现 Runnable 接口创立线程

创立线程的第 2 种办法是实现 Runnable 接口。咱们创立了 NeZhaRunnable 类并实现 Runnable 接口中的 run 办法,如上面代码所示。

public class NeZhaRunnable implements Runnable {public void run() {System.out.println("我是哪吒,我去上路");
    }
}

Thread neZhaPlayer = new Thread(new NeZhaRunnable());
neZhaPlayer.start();

从成果上看,两种形式创立进去的线程成果是一样的。那么,咱们应该怎么抉择?

倡议你应用 Runnable

对于这两种办法,孰优孰劣并没有明确的规定。然而,从面向对象设计的角度来说,举荐你用第二种形式:实现 Runnable 接口

这是因为,在面向对象设计中,有一条约定俗成的规定,组合优于继承(Prefer composition over inheritance),如果没有特地的目标须要重写父类办法,尽量不要应用继承。在 Java 中所有的类都只能是单继承,一旦继承 Thread 之后将不能继承其余类,重大影响类的扩大和灵活性。另外,实现 Runnable 接口也能够与前面的更高级的并发工具联合应用。

所以,相较于继承 Thread,实现 Runnable 接口能够升高代码之间的耦合,放弃更好的灵活性。对于这一准则的更多形容,你能够参考《Effective Java》。

当然,如果你对 Thread 情有独钟,当我没说。此外,在 Java 中咱们还能够通过 ThreadFactory 等工具类创立线程,不过实质上仍是对这两种办法的封装。

四、留神,别踩坑!

线程的启动诚然简略,然而对于一些老手来说,在启动线程的时候,一不小心就会应用 run() 而不是start(),就像上面这样:

Thread neZhaPlayer = new Thread(new NeZhaRunnable());
neZhaPlayer.run();

如果你这么调用的话,你依然能够看到你冀望的输入,然而这正是陷进所在 !这是因为,Runnable 中的run() 办法并不是你所创立的线程调用的,而是调用你这个线程的线程调用的,也就是 主线程 。那为什么间接调用run() 办法也能看到输入呢?这是因为 Thread 中的 run() 会间接调用 target 中的run():

public void run() {if (target != null) {target.run();
    }
}

所以你看,如果你间接调用 run() 的话,并不会创立新的线程。对于这两个办法的执行细节,会在前面的线程状态中剖析,这里你要记住的就是启动线程调用的是start(),而不是run()

以上就是文本的全部内容,祝贺又上了一颗星!

夫子的试炼

用两种不同的形式,创立出两个线程,交差打印 1~100 之间的奇数和偶数,并断点调试。

对于作者

扫码关注公众号,获取及时文章更新。记录平凡人的技术故事,分享有品质(尽量)的技术文章,偶然也聊聊生存和现实。不贩卖焦虑,不抛售课程。

退出移动版