调度机制
-
具体的调度实现分为操作系统和JVM
- 操作系统的调度机制有多种,一般常见的有2种:时间片Unix和抢占式windows
-
所有的Java虚拟机都有一个线程调度器,用来确定那个时刻运行那个线程。主要有两种调度模型:分时调度模型和抢占式调度模型
- 基于时间片轮转法的抢占式调度。线程调度器会给高优先级有更多的运行机会,如果优先级相同则随机选中,执行时长到达时间片后从新进行调度
-
线程的调度不是跨平台的,它不仅取决于Java虚拟机,还依赖于操作系统。在某些操作系统中,即使运行中的线程没有遇到阻塞,也会在运行一段时间后放弃CPU,给其他线程运行的机会
线程的优先级
Java采用的是抢占式的调度机制,提供一个线程调度器来监控程序中启动后进入就绪态的所有线程。线程调度器会按照线程的优先级决定应调度哪个线程来执行
线程的优先级用数字表示,范围从1到10,默认值5。但是需要注意的是优先级的具体实现需要依赖于操作系统,所以Java中优先级需要映射到操作系统上,所以可能会出现操作系统中支持的优先级数量少,Java中多个优先级映射到同一个操作系统优先级上。所以在具体使用中建议优先级的差值应该比较大,建议使用预定义的常量
t2.setPriority(Thread.MAX_PRIORITY);----10
t1.setPriority(Thread.NORM_PRIORITY);-----5默认值
t3.setPriority(Thread.MIN_PRIORITY);-----1
getPriority():int 获取当前线程对象的优先级
setPriority(int):void 设置当前线程对象的优先级,注意修改优先级必须在start()方法调用之前
总结
1、在没有指定线程的优先级的时候,线程都带有普通的优先级。
2、线程的优先级可以分为1到10;10代表最高的优先级,1代表最低的优先级,普通优先级是5.
3、优先级最高的线程在运行时给予优先,但不能保证线程启动后立刻就进入运行状态。
4、与线程池中等待的线程相比,正在运行的线程拥有更高的优先级。
5、由调度程序来决定执行哪一个线程。
6、用setPriority(int)来设定用线程的优先级。
7、在线程的start方法调用之前,应该指定线程的优先级
线程的同步问题
多线程编程中容易出现错误情况,这是由系统的线程调度具有一定随机性造成的,这些情况必须杜绝。
- 线程的执行顺序不可重现,但是执行结果一定可重现
- 解决方案就是同步处理
同步的处理方法1
当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,这种方式有个名称叫互斥锁,即能达到互斥访问目的的锁,也就是说当一个共享数据被当前正在访问的线程加上互斥锁后,在同一个时刻,其他线程只能处于等待的状态,直到当前线程处理完毕释放该锁。
具体编程中使用synchronized关键字可以使用互斥锁。
synchronized将并行改为串行,当然会影响程序的执行效率,执行速度会受到影响。其次synchronized操作线程的堵塞,也就是由操作系统控制CPU的内核进行上下文的切换,这个切换本身也是耗时的。所以使用synchronized关键字会降低程序的运行效率。
编程实现
需求:定义4个线程对同一个num进行加减计算,2个线程各执行50次加,2个线程各执行50次减
1、定义一个类用于封装需要操作的数据和对应的操作方法
//封装数据和对应的操作
public class NumOps {
private int num;//具体操作数据
//提供的方法,业务处理
public void add() {
num=num+1;
System.out.println(Thread.currentThread().getName()+