线程的优先级和线程让步yield

合集下载

线程池调度策略

线程池调度策略

线程池调度策略
线程池调度策略是指在多线程程序中,如何合理地分配和调度各个线程的任务执行。

主要有以下几种调度策略:
1.优先级调度:根据线程的优先级来决定执行顺序,优先级高的线程优先执行。

优先级可以根据线程的属性、任务紧急程度等因素来设定。

2.先来先服务(FCFS):线程提交任务后,按照提交的顺序依次执行。

这种策略简单易实现,但可能导致优先级低的线程长时间得不到执行。

3.最短作业优先(SJF):根据任务估计执行时间的长短来决定执行顺序,执行时间短的线程优先执行。

这种策略能有效减少平均等待时间,但可能导致执行时间长的任务长时间得不到执行。

4.优先级反转:结合优先级调度和先来先服务策略,优先级高的线程在等待时间较长时,可以降低优先级,让优先级低的线程先执行。

这样可以避免低优先级任务长时间得不到执行的问题。

5.时间片轮转:为每个线程分配一个固定的时间片,线程按照顺序执行。

当一个线程的时间片用完后,切换到下一个线程。

这种策略实现了线程的公平执行,但可能导致响应速度较慢。

6.多级反馈队列:将线程分为多个队列,根据线程的优先级和执行情况动态调整队列。

优先级高的线程放在前列,优先执行。

这种策略综合了优先级调度和时间片轮转的优点,实现了较好的
性能。


在实际应用中,可以根据具体需求和场景选择合适的线程池调度策略。

编程思想之多线程与多进程(2)——线程优先级与线程安全

编程思想之多线程与多进程(2)——线程优先级与线程安全

编程思想之多线程与多进程(2)——线程优先级与线程安全线程优先级现在主流操作系统(如Windows、Linux、Mac OS X)的任务调度除了具有前面提到的时间片轮转的特点外,还有优先级调度(Priority Schedule)的特点。

优先级调度决定了线程按照什么顺序轮流执行,在具有优先级调度的系统中,线程拥有各自的线程优先级(Thread Priority)。

具有高优先级的线程会更早地执行,而低优先级的线程通常要等没有更高优先级的可执行线程时才会被执行。

线程的优先级可以由用户手动设置,此外系统也会根据不同情形调整优先级。

通常情况下,频繁地进入等待状态(进入等待状态会放弃之前仍可占用的时间份额)的线程(如IO线程),比频繁进行大量计算以至于每次都把所有时间片全部用尽的线程更受操作系统的欢迎。

因为频繁进入等待的线程只会占用很少的时间,这样操作系统可以处理更多的任务。

我们把频繁等待的线程称之为IO密集型线程(IO Bound Thread),而把很少等待的线程称之为CPU密集型线程(CPU Bound Thread)。

IO密集型线程总是比CPU密集型线程更容易得到优先级的提升。

线程饿死:在优先级调度下,容易出现一种线程饿死的现象。

一个线程饿死是说它的优先级较低,在它执行之前总是有比它优先级更高的线程等待执行,因此这个低优先级的线程始终得不到执行。

当CPU密集型的线程优先级较高时,其它低优先级的线程就很可能出现饿死的情况;当IO密集型线程优先级较高时,其它线程相对不容易造成饿死的善,因为IO线程有大量的等待时间。

为了避免线程饿死,调度系统通常会逐步提升那些等待了很久而得不到执行的线程的优先级。

这样,一个线程只要它等待了足够长的时间,其优先级总会被提升到可以让它执行的程度,也就是说这种情况下线程始终会得到执行,只是时间的问题。

在优先级调度环境下,线程优先级的改变有三种方式:1. 用户指定优先级;2. 根据进入等待状态的频繁程度提升或降低优先级(由操作系统完成);3. 长时间得不到执行而被提升优先级。

LabVIEW程序中的线程线程的优先级

LabVIEW程序中的线程线程的优先级

LabVIEW 程序中的线程3 - 线程的优先级三、线程的优先级在VI 的属性设置面板VI Properties -> Execution 中还有一个下拉选项控件是用来设置线程优先级的(Priority)。

这一选项可以改变这个VI 运行线程的优先级。

优先级设置中共有六项,其中前五项是分别从低到高的五个优先级。

优先级越高,越容易抢占到CPU 资源。

比如你把某个负责运算的VI 的优先级设为最高级(time critical priority),程序在运行时,CPU 会更频繁地给这个VI 所在线程分配时间片段,其代价是分配给其它线程的运算时间减少了。

如果这个程序另有一个线程负责界面刷新,那么用户会发现在把执行线程的优先级提高后,界面刷新会变得迟钝,甚至根本就没有响应。

优先级设置的最后一项是subroutine,它与前五项别有很大的不同。

严格的说subroutine 不能作为一个优先级,设置subroutine 会改变VI 的一些属性:设置为subroutine 的VI 的前面板的信息会被移除。

所以这样的VI 不能用作界面,也不能单独执行。

设置为subroutine 的VI 的调试信息也会被移除。

这样的VI 无法被调试。

当程序执行到被设置为subroutine 的VI 的时候,程序会暂时变为单线程执行方式。

即程序在subroutine VI 执行完之前,不会被别的线程打断。

以上的三点保证了subroutine VI 在执行时可以得到最多的CPU 资源,某些作为关键运算的VI,又不是特别耗时的,就可以被设置为subroutine 以提高运行速度。

比如有这样一个VI,他的输入是一个数值数组,输出是这组数据的平均值。

这个运算在程序中需要被尽快完成,以免拖延数据的显示,这个VI 就是一个蛮适合的subroutine VI。

在设置VI 优先级的时候有几点需要注意的。

提高一个VI 的优先级一般不能显著缩短程序的运行时间。

【转】pthread设置线程的调度策略和优先级

【转】pthread设置线程的调度策略和优先级

【转】pthread设置线程的调度策略和优先级线程的调度有三种策略:SCHED_OTHER、SCHED_RR和SCHED_FIFO。

Policy⽤于指明使⽤哪种策略。

下⾯我们简单的说明⼀下这三种调度策略。

SCHED_OTHER(是Linux默认的分时调度策略)它是默认的线程分时调度策略,所有的线程的优先级别都是0,线程的调度是通过分时来完成的。

简单地说,如果系统使⽤这种调度策略,程序将⽆法设置线程的优先级。

请注意,这种调度策略也是抢占式的,当⾼优先级的线程准备运⾏的时候,当前线程将被抢占并进⼊等待队列。

这种调度策略仅仅决定线程在可运⾏线程队列中的具有相同优先级的线程的运⾏次序。

SCHED_FIFO它是⼀种实时的先进先出调⽤策略,且只能在超级⽤户下运⾏。

这种调⽤策略仅仅被使⽤于优先级⼤于0的线程。

它意味着,使⽤SCHED_FIFO的可运⾏线程将⼀直抢占使⽤SCHED_OTHER的运⾏线程J。

此外SCHED_FIFO是⼀个⾮分时的简单调度策略,当⼀个线程变成可运⾏状态,它将被追加到对应优先级队列的尾部((POSIX 1003.1)。

当所有⾼优先级的线程终⽌或者阻塞时,它将被运⾏。

对于相同优先级别的线程,按照简单的先进先运⾏的规则运⾏。

我们考虑⼀种很坏的情况,如果有若⼲相同优先级的线程等待执⾏,然⽽最早执⾏的线程⽆终⽌或者阻塞动作,那么其他线程是⽆法执⾏的,除⾮当前线程调⽤如pthread_yield之类的函数,所以在使⽤SCHED_FIFO的时候要⼩⼼处理相同级别线程的动作。

SCHED_RR鉴于SCHED_FIFO调度策略的⼀些缺点,SCHED_RR对SCHED_FIFO做出了⼀些增强功能。

从实质上看,它还是SCHED_FIFO调⽤策略。

它使⽤最⼤运⾏时间来限制当前进程的运⾏,当运⾏时间⼤于等于最⼤运⾏时间的时候,当前线程将被切换并放置于相同优先级队列的最后。

这样做的好处是其他具有相同级别的线程能在“⾃私“线程下执⾏。

linux 线程优先级设置方法

linux 线程优先级设置方法

linux 线程优先级设置方法Linux操作系统中,线程是轻量级的进程,合理设置线程的优先级可以优化系统资源的分配,提高程序的执行效率。

本文将详细介绍Linux线程优先级的设置方法。

一、线程优先级概述在Linux操作系统中,线程优先级通常分为两种:静态优先级和动态优先级。

1.静态优先级:在创建线程时分配的优先级,通常在程序运行过程中不会改变。

2.动态优先级:系统根据线程的运行情况动态调整的优先级,通常与线程的CPU使用时间、等待时间等因素有关。

二、设置线程优先级的方法1.使用sched_setparam()函数设置静态优先级函数原型:```cint sched_setparam(pid_t pid, const struct sched_param *param);```示例代码:```c#include <stdio.h>#include <unistd.h>#include <sched.h>#include <pthread.h>void *thread_function(void *arg) {// 线程函数代码}int main() {pthread_t tid;struct sched_param param;int policy;// 创建线程pthread_create(&tid, NULL, thread_function, NULL);// 获取当前线程的调度策略和优先级pthread_getschedparam(pthread_self(), &policy, &param);// 设置优先级(数值越大,优先级越高)param.sched_priority = 30;// 设置线程优先级if (pthread_setschedparam(tid, policy, &param) != 0) { perror("pthread_setschedparam");return 1;}// 等待线程结束pthread_join(tid, NULL);return 0;}```2.使用nice()函数设置动态优先级函数原型:```cint nice(int inc);```示例代码:```c#include <stdio.h>#include <unistd.h>#include <sys/resource.h>int main() {// 获取当前进程的nice值int old_nice = nice(0);// 设置新的nice值(数值越小,优先级越高)if (nice(-10) == -1) {perror("nice");return 1;}// 输出新的优先级printf("New priority: %d", old_nice - 10);return 0;}```三、总结本文介绍了Linux线程优先级的设置方法,包括使用sched_setparam()函数设置静态优先级和使用nice()函数设置动态优先级。

线程的优先级和线程让步yield

线程的优先级和线程让步yield

2、线程的优先级和线程让步yield()线程的让步是通过Thread.yield()来实现的。

yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。

要理解yield(),必须了解线程的优先级的概念。

线程总是存在优先级,优先级范围在1~10之间。

JVM线程调度程序是基于优先级的抢先调度机制。

在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。

但这仅仅是大多数情况。

注意:当设计多线程应用程序的时候,一定不要依赖于线程的优先级。

因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。

当线程池中线程都具有相同的优先级,调度程序的JVM实现自由选择它喜欢的线程。

这时候调度程序的操作有两种可能:一是选择一个线程运行,直到它阻塞或者运行完成为止。

二是时间分片,为池内的每个线程提供均等的运行机会。

设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。

可以通过setPriority(int newPriority)更改线程的优先级。

例如:Thread t = new MyThread();t.setPriority(8);t.start();线程优先级为1~10之间的正整数,JVM从不会改变一个线程的优先级。

然而,1~10之间的值是没有保证的。

一些JVM可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。

线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:static int MAX_PRIORITY线程可以具有的最高优先级。

static int MIN_PRIORITY线程可以具有的最低优先级。

static int NORM_PRIORITY分配给线程的默认优先级。

3、Thread.yield()方法Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。

Java程序设计任务驱动式教程 任务二十八 线程的生命周期与优先级(线程的状态与调度)

Java程序设计任务驱动式教程 任务二十八 线程的生命周期与优先级(线程的状态与调度)
章目录
28.4 必备知识
4. 阻塞状态(Block) 由于某种原因使得运行中的线程不能继续执行,该线程进行阻塞态。此时 线程不会被分配CPU时间,无法执行。Java中提供了大量的方法来阻 塞线程。下面简单介绍几个。 sleep() 方法:指定在指定的时间内处于阻塞状态。指定的时间一过, 线程进入可执行状态。 Wait()方法: 使得线程进行阻塞状态。它有两种格式:一种是允许指 定以毫秒为单位的一段时间内作为参数。该格式可以用notify()方法被 调用或超出指定时间时,线程可重新进入可运行状态。另一种格式没 有格式,该格式必须是notify()方法被调用后才能使线程进行可运行状 态。 5.死亡状态(Dead) 正常情况下,当线运行结束后进入死亡状态。有两种情况导致线程进 入死亡状态:自然撤销或被停止。当运行run()方法结束时,该线程就 自动自然撤销,当一个应用程序因故停止运行时,系统将终止该程序 正在执行的所有线程。当然也可以调用stop()方法来终止线程。但一 般不推荐使用,因为会产生异常情况。
第1章目录
7/19
28.2 实现方案
问题分析 本任务是创建一个Java多线程状态设置与线程调度应用程序,首先创建一个 普通类EatApple,在此类中创建两个方法。第一个方法为put()方法,实 现将苹果放入到盘子中。第二个方法为get()方法,实现将从盘子中取苹 果。然后再创建两个线程来分别调用put()方法和get()方法来完成苹果的 取放操作。 解决步骤 1.打开Eclipse,在study项目中创建包com.task28,再确定类名EatApple。得到 类的框架。 2.在public class EatApple{下面一行输入类的属性描述:
12/19 12/
28.3 代码分析

yield的用法详解

yield的用法详解

yield的用法详解一、什么是yield?yield是Python中的一个关键字,用于生成器函数(generator function)中。

生成器函数是一种特殊的函数,它可以在调用时暂停执行,并且在下次调用时从上次暂停的位置继续执行。

二、yield的基本语法在生成器函数中,我们可以使用yield语句将一个值返回给调用者。

以下是yield语句的基本语法:```pythonyield expression```其中,expression表示要返回的值。

三、yield语句工作原理当生成器函数被调用时,它并不会立即执行内部代码,而是返回一个迭代器(iterator)。

每次调用迭代器的__next__()方法或使用for循环进行迭代时,生成器函数才会开始执行内部代码,并在遇到yield语句时暂停执行,并将 yield 后面的表达式作为返回值。

四、生成器函数中多个yield语句的执行顺序在生成器函数内部可以有多个 yielf 语句。

当生成器被调用时,会按照顺序依次执行每个 yield 语句,并在每次遇到 yield 时暂停并返回一个值。

下次调用迭代器的__next__()方法或使用 for 循环进行迭代时,则会从上一次暂停处继续执行。

五、通过for循环迭代生成器生成器函数通常与 for 循环一起使用,方便迭代生成器的返回值。

当使用 for 循环迭代生成器时,会自动调用迭代器的__next__()方法,并将返回值赋值给循环变量。

六、利用yield实现惰性求值惰性求值是一种节省资源的编程技巧,它允许在需要时逐步计算结果。

生成器函数中的 yield 语句可以实现这一特性。

当生成器函数内部存在复杂且耗时的计算过程时,可以使用 yield 在每次迭代时进行部分计算并返回中间结果,从而避免处理大量数据导致的内存占用和时间开销。

七、应用场景举例-斐波那契数列斐波那契数列是一个经典的应用场景,可以通过生成器函数和 yield 语句非常简洁地实现。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2、线程的优先级和线程让步yield()
线程的让步是通过Thread.yield()来实现的。

yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。

要理解yield(),必须了解线程的优先级的概念。

线程总是存在优先级,优先级范围在1~10之间。

JVM线程调度程序是基于优先级的抢先调度机制。

在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。

但这仅仅是大多数情况。

注意:当设计多线程应用程序的时候,一定不要依赖于线程的优先级。

因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。

当线程池中线程都具有相同的优先级,调度程序的JVM实现自由选择它喜欢的线程。

这时候调度程序的操作有两种可能:一是选择一个线程运行,直到它阻塞或者运行完成为止。

二是时间分片,为池内的每个线程提供均等的运行机会。

设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。

可以通过setPriority(int newPriority)更改线程的优先级。

例如:
Thread t = new MyThread();
t.setPriority(8);
t.start();
线程优先级为1~10之间的正整数,JVM从不会改变一个线程的优先级。

然而,1~10之间的值是没有保证的。

一些JVM可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。

线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:
static int MAX_PRIORITY
线程可以具有的最高优先级。

static int MIN_PRIORITY
线程可以具有的最低优先级。

static int NORM_PRIORITY
分配给线程的默认优先级。

3、Thread.yield()方法
Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。

yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。

因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。

但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。

在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

4、join()方法
Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。

在A执行完毕之前,B不能工作。

例如:
Thread t = new MyThread();
t.start();
t.join();
另外,join()方法还有带超时限制的重载版本。

例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。

线程的加入join()对线程栈导致的结果是线程栈发生了变化,当然这些变化都是瞬时的。

下面给示意图:小结
到目前位置,介绍了线程离开运行状态的3种方法:
1、调用Thread.sleep():使当前线程睡眠至少多少毫秒(尽管它可能在指定的时间之前被中断)。

2、调用Thread.yield():不能保障太多事情,尽管通常它会让当前运行线程回到可运行性状态,使得有相同优先级的线程有机会执行。

3、调用join()方法:保证当前线程停止执行,直到该线程所加入的线程完成为止。

然而,如果它加入的线程没有存活,则当前线程不需要停止。

除了以上三种方式外,还有下面几种特殊情况可能使线程离开运行状态:
1、线程的run()方法完成。

2、在对象上调用wait()方法(不是在线程上调用)。

3、线程不能在对象上获得锁定,它正试图运行该对象的方法代码。

4、线程调度程序可以决定将当前运行状态移动到可运行状态,以便让另一个线程获得运行机会,而不需要任何理由。

一、同步问题提出
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。

例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据。

public class Foo {
private int x = 100;
public int getX() {
return x;
}
public int fix(int y) {
x = x - y;
return x;
}
}
public class MyRunnable implements Runnable {
private Foo foo = new Foo();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread ta = new Thread(r, "Thread-A");
Thread tb = new Thread(r, "Thread-B");
ta.start();
tb.start();
}
public void run() {
for (int i = 0; i < 3; i++) {
this.fix(30);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
+ " : 当前foo对象的x值= " + foo.getX());
}
}
public int fix(int y) {
return foo.fix(y);
}
}
运行结果:
Thread-A : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= -20
Thread-A : 当前foo对象的x值= -50
Thread-A : 当前foo对象的x值= -80
Thread-B : 当前foo对象的x值= -80
Process finished with exit code 0
从结果发现,这样的输出值明显是不合理的。

原因是两个线程不加控制的访问Foo对象并修改其数据所致。

如果要保持结果的合理性,只需要达到一个目的,就是将对Foo的访问加以限制,每次只能有一个线程在访问。

这样就能保证Foo对象中数据的合理性了。

在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源类Foo变量x标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。

相关文档
最新文档