java 实时同步图形_实时Java,线程化和同步

【IT168 技术文章】线程化和同步是 Java 编程语言的核心特性,Java 语言规范(JLS)中对二者作出了描述。RTSJ 用多种方式扩展了 JLS 的核心功能。例如,RTSJ 引入了一些新的实时(RT)线程类型,它们必须遵守比普通 Java 线程更加严格的调度策略。另一个例子是优先级继承,它是一种锁定策略,定义了锁竞争时如何管理锁同步。

理解对优先级和优先级序列的管理有助于理解 RTSJ 针对线程化和同步所作的更改。优先级也是 RT 应用程序使用的一种重要工具。本文通过讨论如何管理线程优先级和优先级序列来描述 RTSJ 线程化和同步。

理解普通的 Java 线程

JLS 中定义的线程称为普通 Java 线程。普通 Java 线程是 java.lang.Thread 类的一个实例,该类拥有从 1 到 10 的 10 个优先级别。为了适应大量的执行平台,JLS 在如何实现、调度和管理普通 Java 线程的优先级方面提供了很大的灵活性。

WebSphere VMs on Linux®(包括 WebSphere Real Time)使用 Linux 操作系统提供的本地线程化服务。您可以通过理解 Linux 的线程化和同步来学习 Java 的线程化和同步。

Linux 线程化和同步

Linux 操作系统发展至今已经提供了不同用户级别的线程化实现。Native POSIX Thread Library(NPTL)是 Linux 最新版本的战略性线程化实现,由 WebSphere VMs 所使用。NPTL 与它的前任相比优势在于 POSIX 兼容性和性能。在编译时可通过系统的头文件获取 POSIX 服务。可在运行时通过 libpthread.so 动态库和底层 Linux 核心支持获取 POSIX 服务。Linux 核心可以根据静态控制(如线程优先级级别)和系统中执行的线程的某些动态条件下来执行线程调度。

POSIX 允许您创建具有不同线程调度策略和优先级的 POSIX 线程(pthreads)以满足不同应用程序的需求。下面是三种此类的调度策略:

SCHED_OTHER

SCHED_FIFO

SCHED_RR

SCHED_OTHER 策略用于传统用户任务,如程序开发工具、办公应用程序和 Web 浏览器。 SCHED_RR 和 SCHED_FIFO 主要用于具有更高的确定性和时限需求的应用程序。SCHED_RR 和 SCHED_FIFO 之间的主要区别是 SCHED_RR 分时间片 执行线程,而 SCHED_FIFO 则不是这样。SCHED_OTHER 和 SCHED_FIFO 策略用于 WebSphere Real Time,并在下面作出了更加详细的描述。(我们不介绍 SCHED_RR 策略,WebSphere Real Time 没有使用它。)

POSIX 通过 pthread_mutex 数据类型提供锁定和同步支持。pthread_mutex 可以使用不同的锁定策略创建。当多个线程需要同时获取同一个锁的时候,锁定策略常常会影响执行行为。标准的 Linux 版本支持单个的默认策略,而 RT Linux 版本还支持优先级继承锁定策略。

Linux 调度和锁定用来管理先进先出(FIFO)队列。

普通 Java 线程的线程调度

RTSJ 指出普通 Java 线程的行为跟 JLS 中定义的相同。在 WebSphere Real Time 中,普通 Java 线程使用 Linux 的 POSIX SCHED_OTHER 调度策略来实现。SCHED_OTHER 策略主要用于编译器和字处理程序之类的应用程序,不能用于需要更高确定性的任务。

在 2.6 Linux 内核中,SCHED_OTHER 策略支持 40 个优先级级别。这 40 个优先级级别基于处理器级别来管理,就是说:

出于缓存性能的原因,Linux 尝试在同一个处理程序中执行线程。

线程调度主要使用处理器级别的锁而不是系统级别的锁。

如有需要,Linux 可将线程从一个处理程序迁移到另一个处理程序以平衡工作量。

在(40 个中的)每个优先级级别中,Linux 管理活动队列 和过期队列。每个队列包含一个线程链表(或者为空)。使用活动和过期队列出于以下目的:效率、负载平衡和其他一些目的。逻辑上可将系统看作:为(40 个中的)每个优先级管理一个 FIFO 序列,称为运行队列。一个从非空运行队列的前端分派的线程具有最高的优先级。该线程从队列中移除并执行一段时间(称作:时间量 或时间片)。当一个执行线程超过 它的时间量时,它的优先级被放在运行队列的后端并给它指定了新的时间量。通过从队列的前端分派线程和在队列的后端放置过期的线程,程序在一个优先级中轮替执行。

为线程提供的时间量取决于给线程指定的优先级。指定了较高优先级的线程拥有较长的执行时间量。为了防止线程霸占 CPU,Linux 根据一些因素(如线程是 I/O 限制还是 CPU 限制)动态提高或降低线程的优先级。线程可以通过让步(如调用 Thread.yield())自愿地放弃它的时间片,或通过阻塞放弃控制权,在阻塞处等待事件发生。释放锁可以触发一个这类的事件。

WebSphere Real Time 中的 VM 没有显式地指定跨越 40 个 SCHED_OTHER Linux 线程优先级的 10 个普通 Java 线程优先级。所有的普通 Java 线程,不论其 Java 优先级如何,都被指定为默认的 Linux 优先级。默认的 Linux 优先级处于 40 个 SCHED_OTHER 优先级的中间位置。通过使用默认优先级,普通 Java 线程可以顺利地执行,即不论 Linux 可能作出何种动态优先级调整,运行队列中的每个普通 Java 线程都能最终得到执行。这里假设的是只执行普通 Java 线程的系统而不是其他系统,比如执行 RT 线程的系统。

注意:WebSphere Real Time 中的 VM 和 WebSphere VM 的非 RT 版本都使用 SCHED_OTHER 策略并针对普通 Java 线程使用默认优先级指定。通过使用相同的策略,这两种 JVM 具有相似但不相同的线程调度和同步特征。WebSphere Real Time 类库中的更改、JVM 中的更改和为支持 RTSJ 而在 JIT 编译器中作出的更改,以及 RT Metronome 垃圾收集器的引入使应用程序不可能在两种虚拟机中以相同的同步和性能特征运行。在 IBM WebSphere Real Time 测试期间,在测试程序中,同步差异使竞争条件(换言之,bug)浮出了水面,而这些测试程序已经在其他 JVM 上运行了很多年。

使用普通 Java 线程的代码示例

清单 1 展示了一个使用普通 Java 线程的程序,确定了两个线程中的每一个在五秒的时间间隔内在一个循环中执行的迭代次数:

清单 1. 普通 Java 线程

1 classmyThreadClassextendsjava.lang.Thread {2 volatilestaticbooleanStop=false;3 4 //Primordial thread executes main()5 publicstaticvoidmain(String args[])throwsInterruptedException {6 7 //Create and start 2 threads8 myThreadClass thread1=newmyThreadClass();9 thread1.setPriority(4);//1st thread at 4th non-RT priority10 myThreadClass thread2=newmyThreadClass();11 thread2.setPriority(6);//2nd thread at 6th non-RT priority12 thread1.start();//start 1st thread to execute run()13 thread2.start();//start 2nd thread to execute run()14 15 //Sleep for 5 seconds, then tell the threads to terminate16 Thread.sleep(5*1000);17 Stop=true;18 }19 20 publicvoidrun() {//Created threads execute this method21 System.out.println("Created thread");22 intcount=0;23 for(;Stop!=true;) {//continue until asked to stop24 count++;25 Thread.yield();//yield to other thread26 }27 System.out.println("Thread terminates. Loop count is"+count);28 }29 }30

清单 1 中的程序具有三个普通 Java 线程的用户线程:

原始线程:

它是启动过程中隐式创建的主线程,执行 main() 方法。

main() 创建了两个普通 Java 线程:一个线程的优先级为 4 而另一个线程的优先级为 6。

主线程通过调用 Thread.sleep() 方法休眠五秒钟来达到故意阻塞自身的目的。

休眠五秒钟后,此线程指示其他两个线程结束。

优先级为 4 的线程:

此线程由原始线程创建,后者执行包含 for 循环的 run() 方法。

该线程:

在每次循环迭代中增加一个计数。

通过调用 Thread.yield() 方法自愿放弃它的时间片。

在主线程发出请求时结束。结束前打印循环计数。

优先级为 6 的线程:此线程执行的动作与优先级为 4 的线程相同。

如果此程序在单处理器或卸载的多处理器上运行,则每个线程打印的 for 循环迭代计数大致相同。在一次运行中,程序将打印:

1 Created thread2 Created thread3 Thread terminates. Loop count is5400844 Thread terminates. Loop count is5400835

如果删除对 Thread.yield() 的调用,则两个线程的循环计数可能相近,但绝不可能相同。在 SCHED_OTHER 策略中为这两个线程都指定了相同的默认优先级。因此给两个线程分配了相同的时间片执行。因为线程执行的是相同的代码,所以它们应作出类似的动态优先级调整并在相同的运行队列中轮替执行。但是由于首先执行优先级为 4 的线程,因此在五秒钟的执行时间间隔中,它分得的时间稍多一些并且打印的循环计数也稍大一些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值