【Ruby高级技术】在项目中使用多线程之后的一系列问题解决方案-同步控制、异常处理、死锁处理

简介: 【Ruby高级技术】在项目中使用多线程之后的一系列问题解决方案-同步控制、异常处理、死锁处理

多线程的运用

def func2
   j=0
   while j<=2
      puts "func2 at: #{Time.now}"
      sleep(1)
      j=j+1
   end
end

1.new可以用于创建线程,Thread也可以使用相同的语法Start或Thread。fork用于创建线程。
2.创建线程后,无需启动,线程将自动执行。
3.Thread类定义了一些处理线程的方法。线程执行thread.new中的代码块。
4.线程代码块中的最后一条语句是线程的值,它可以通过线程的方法调用。如果线程完成执行,则返回线程值;否则,在线程完成执行之前,不会返回该值。
5.线程。当前方法返回表示当前线程的对象。线main方法返回主线程。
6.通过Thread Join方法执行线程。此方法将暂停主线程,直到当前线程完成执行。

puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

系统上运行的每个程序都是一个进程。每个进程包含一个或多个线程。
线程是程序中的单序列控制流。在一个程序中同时运行多个线程以完成不同的工作称为多线程。
在Ruby中,我们可以通过Thread类创建多个线程。Ruby线程是轻量级的,可以以高效的方式实现并行代码。

def func1
   i=0
   while i<=2
      puts "func1 at: #{Time.now}"
      sleep(2)
      i=i+1
   end
end

线程发生异常

当线程发生异常且未被救援捕获时,通常会在没有警告的情况下终止线程。但是,如果其他线程由于thread#join关系一直在等待该线程,则等待线程也将抛出相同的异常。

begin
  t = Thread.new do
    Thread.pass 
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

主线程确实在等join。
使用以下三种方法,可以在线程因异常而终止时中断解释器。

  • 在启动脚本时指定-d选项,并在调试模式下运行它。
  • 使用Thread.art_on_exception设置标志。
  • 使用线程#abort_on_Exception设置指定线程的标志。

当使用上述三种方法之一时,整个解释器将被中断。

同步控制

在Ruby中,提供了三种同步方法:
1.通过Mutex类实现线程同步
2.用于监控数据切换的Queue类实现线程同步
3.使用ConditionVariable实现同步控制
通过Mutex类进行线程同步
Mutex类实现线程同步控制。如果同时需要多个线程时钟使用程序变量,则可以使用lock来锁定该变量。代码如下:

@num=200
@mutex=Mutex.new
 
def buyTicket(num)
     @mutex.lock
          if @num>=num
               @num=@num-num
               puts "you have successfully bought #{num} tickets"
          else
               puts "sorry,no enough tickets"
          end
     @mutex.unlock
end
 
ticket1=Thread.new 10 do
     10.times do |value|
     ticketNum=15
     buyTicket(ticketNum)
     sleep 0.01
     end
end
 
ticket2=Thread.new 10 do
     10.times do |value|
     ticketNum=20
     buyTicket(ticketNum)
     sleep 0.01
     end
end

除了使用锁锁定变量外,还可以使用try_lock锁定变量。您也可以使用Mutex.synchronize来同步对变量的访问。
用于监视数据切换的Queue类实现线程同步
Queue类表示支持线程并可以同步访问队列末尾的队列。不同的线程可以使用一对统一的类,但不要担心队列中的数据是否可以同步。此外,使用SizedQueue类可以限制队列的长度
SizedQueue类可以帮助我们非常方便地开发线程同步应用程序。只要我们加入这个队列,就不需要关心线程同步。

sleep 1
ticket1.join
ticket2.join

线程可以有自己的私有变量

线程可以有自己的私有变量,在创建线程时将其写入线程。它可以在线程范围内使用,但不能在线程外共享。
但有时,如果一个线程的局部变量需要由另一个线程或主线程访问呢?Ruby提供了按名称创建线程变量的能力,类似地将线程视为哈希表。通过[]=写入数据,通过[]读取数据。

count = 0
arr = []
 
10.times do |i|
   arr[i] = Thread.new {
      sleep(rand(0)/10.0)
      Thread.current["mycount"] = count
      count += 1
   }
end

线程的优先级是影响线程调度的主要因素。其他因素包括CPU的执行时间、线程分组调度等。
您可以使用线程。priority方法获取线程优先级和线程。priority=调整线程优先级的方法。
默认情况下,线程的优先级为0。优先级越高,执行速度越快。
一个线程可以访问其自身范围内的所有数据,但如果它需要访问线程中其他线程的数据。
Thread类为线程提供了一种访问彼此数据的方法。您可以简单地将线程用作哈希表。您可以使用[]=在任何线程中写入数据,使用[]读取数据。

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end

死锁处理

当两个或多个计算单元正在等待对方停止运行以获取系统资源,但都没有提前退出时,这种情况称为死锁。
例如,进程p1占用显示器并且必须使用打印机,而打印机被进程p2占用并且p2必须使用显示器,这形成了死锁。
当使用Mutex对象时,我们需要注意线程死锁。

cv = ConditionVariable.new
a = Thread.new {
   mutex.synchronize {
      puts "A: I have critical section, but will wait for cv"
      cv.wait(mutex)
      puts "A: I have critical section again! I rule!"
   }
}
 
puts "(Later, back at the ranch...)"
 
b = Thread.new {
   mutex.synchronize {
      puts "B: Now I am critical, but am done with cv"
      cv.signal
      puts "B: I am still critical, finishing up"
   }
}

通常,正常的程序执行路径是单行执行。按编码顺序执行程序中的所有语句。然而,在多线程程序中,可以在多个路径中执行多个程序。多线程使用更少的内存空间并共享相同的地址空间。多线程用于同时执行多个任务。
创建线程后,无需启动线程。它在获得正确的CPU资源后自动运行。块中的最后一个表达式是线程的值。如果线程完全运行,value方法将返回线程值。否则,value方法将在线程完成时阻塞并返回。线程类在运行查询和操作线程时定义了一些方法。
通过调用线程的Thread.java方法。

相关文章
|
2月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
59 5
|
1月前
|
Java 数据库 开发者
探索研究Ruby 多线程
【9月更文挑战第4天】
31 2
|
1月前
|
监控 Java
线程池中线程异常后:销毁还是复用?技术深度剖析
在并发编程中,线程池作为一种高效利用系统资源的工具,被广泛用于处理大量并发任务。然而,当线程池中的线程在执行任务时遇到异常,如何妥善处理这些异常线程成为了一个值得深入探讨的话题。本文将围绕“线程池中线程异常后:销毁还是复用?”这一主题,分享一些实践经验和理论思考。
51 3
|
2月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
81 5
|
2月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
23 3
|
2月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
86 1
|
2月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
34 1
|
2月前
|
API Windows
揭秘网络通信的魔法:Win32多线程技术如何让服务器化身超级英雄,同时与成千上万客户端对话!
【8月更文挑战第16天】在网络编程中,客户/服务器模型让客户端向服务器发送请求并接收响应。Win32 API支持在Windows上构建此类应用。首先要初始化网络环境并通过`socket`函数创建套接字。服务器需绑定地址和端口,使用`bind`和`listen`函数准备接收连接。对每个客户端调用`accept`函数并在新线程中处理。客户端则通过`connect`建立连接,双方可通过`send`和`recv`交换数据。多线程提升服务器处理能力,确保高效响应。
40 6
|
2月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
34 0
|
2月前
|
Java 测试技术 Android开发
Android项目架构设计问题之构造一个Android中的线程池如何解决
Android项目架构设计问题之构造一个Android中的线程池如何解决
24 0
下一篇
无影云桌面