创建线程
本课程讨论了创建、运行、优先级设置以及检查线程状态的各种方法。
创建线程
我们可以使用 Thread 类的以下类方法来创建线程:
new()start()fork()
注意,这些方法都会同时创建并启动线程。
下面是一个使用 new() 方法创建线程并传递参数的示例。
1# 示例:展示如何使用 Thread.new 创建线程 2 3Thread.current.name = "mainThread" 4 5# 启动一个子线程 6thread = Thread.new("Hello", "World") { |arg1, arg2| 7 Thread.current.name = "childThread" 8 puts("名称 #{Thread.current.name},ID #{Thread.current.__id__} 说 #{arg1} #{arg2}") 9} 10 11# 等待线程结束 12thread.join() 13 14puts("名称 #{Thread.current.name},ID #{Thread.current.__id__}")
在 第6行,我们使用 Thread.new 类方法来实例化并运行线程。下面的两个代码片段展示了使用另外两种类方法创建线程的相同逻辑。
1# 示例:展示如何使用 Thread.start 创建线程 2 3Thread.current.name = "mainThread" 4 5# 启动一个子线程 6thread = Thread.start("Hello", "World") { |arg1, arg2| 7 Thread.current.name = "childThread" 8 puts("名称 #{Thread.current.name},ID #{Thread.current.__id__} 说 #{arg1} #{arg2}") 9} 10 11# 等待线程结束 12thread.join() 13 14puts("名称 #{Thread.current.name},ID #{Thread.current.__id__}")
使用 Thread.fork:
1# 示例:展示如何使用 Thread.fork 创建线程 2 3Thread.current.name = "mainThread" 4 5# 启动一个子线程 6thread = Thread.fork("Hello", "World") { |arg1, arg2| 7 Thread.current.name = "childThread" 8 puts("名称 #{Thread.current.name},ID #{Thread.current.__id__} 说 #{arg1} #{arg2}") 9} 10 11# 等待线程结束 12thread.join() 13 14puts("名称 #{Thread.current.name},ID #{Thread.current.__id__}")
继承 Thread 类
另一种创建线程的方式是继承 Thread 类,并使用派生类的实例。下面是一个示例:
1class MyThread < Thread 2 def initialize 3 puts("在 MyThread 初始化器中") 4 5 # 必须调用父类的初始化方法 6 super 7 end 8end 9 10 11myThread = MyThread.new do 12 puts("正在运行 Thread 子类的一个实例") 13end 14 15 16myThread.join() 17 18puts("主线程退出")
注意,在 第6行,我们使用了关键字 super,它会调用父类中同名的方法,并传递相同的参数。如果注释掉 第6行,程序将无法运行。
另外两个类方法 start() 和 fork() 的行为略有不同,它们会忽略并跳过派生类的 initialize() 方法。
考虑下面的代码片段,注意 第3行 的 initialize() 中的打印信息不会被输出。
1class MyThread < Thread 2 def initialize 3 puts("在 MyThread 初始化器中") 4 end 5 6 def sayHi 7 puts("你好世界。注意初始化器未被执行。") 8 end 9end 10 11 12myThread = MyThread.start() { 13 myThread.sayHi() 14} 15 16 17myThread.join() 18 19puts("主线程退出")
以下示例使用 fork() 方法。同样地,第4行 的打印信息也不会出现。
1class MyThread < Thread 2 def initialize 3 # 不会被打印 4 puts("在 MyThread 初始化器中") 5 end 6 7 def sayHi 8 puts("你好世界。注意初始化器未被执行。") 9 end 10end 11 12 13myThread = MyThread.fork do 14 myThread.sayHi() 15end 16 17 18myThread.join() 19 20puts("主线程退出")
线程状态
每个线程都维护一个 status,用于表示其当前所处的状态。线程在不同时间可能处于多种状态之一。status 可通过以下方式访问:
1Thread.current.status
以下是 status 的可能取值及其含义:
- run线程当前正在运行。
- sleep线程当前正在等待或阻塞。
- false线程已成功执行完毕或已被终止。
- nil抛出了未处理的异常。
- aborting线程正在终止。
下面是一个检查线程 status 的完整示例。
1t1 = Thread.new { loop {} } 2t2 = Thread.new { sleep 5 } 3t3 = Thread.new { Thread.exit } 4t4 = Thread.new { raise "exception" } 5 6# 让主线程等待其他线程启动 7sleep 1 8 9puts s1 = t1.status # run 10puts s2 = t2.status # sleep 11puts s3 = t3.status # false 12puts s4 = t4.status # nil
线程优先级
priority 表示线程被调度器执行的频繁程度。优先级较高的线程比优先级较低的线程更频繁地运行。priority 可以通过整数设置。下面的例子演示了线程中 priority 的工作方式。两个不同的线程分别维护计数器,并根据设定的优先级进行运行。
1count_t1 = 0 2count_t2 = 0 3 4t1 = Thread.new do 5 loop { count_t1 += 1 } 6 end 7t1.priority = 2 8 9t2 = Thread.new do 10 loop { count_t2 += 1 } 11 end 12t2.priority = 1 13 14sleep 1 15puts count_t1 16puts count_t2
从输出可以看出,优先级更高的线程获得了更大的计数值,因为它比另一个线程更频繁地运行。