由于在程序中使用多线程,如何合理安排线程的执行顺序? 即哪些线程应该先执行,哪些应该后执行?

参考文章:https://juejin.im/post/5d897125e51d4557dc774f6f

线程类的方法

(1) 线程的构造方法:

  • public Thread()
  • public Thread(String name)
  • public Thread(Runnable target)
  • public Thread(Runnable target, String name)

(2)线程的类方法:
以下是 Thread类的主要静态方法, 即可以直接从 Thread类调用。

  • CurrentThread() 返回正在运行的 Thread对象名称。
  • sleep(long n) 让当前线程休眠 n 毫秒。
  • sleep(long , int ) 使一个线程休眠 long 毫秒 int 纳秒
  • yield() 挂起当前线程, 使其他处于等待状态的线程运行

(3)实例方法

  • start() 启动一个线程, 这个线程将会自动调用 run 方法, 同时,在新的线程开始执行时,调用 start 的那个线程将立即返回执行主程序。

控制线程的优先级

尽管从概念上来说线程能够同步运行,但事实上存在着差别,如果计算机由多个 CPU则没有问题,但大部分计算机都是一个 CPU, 一个时刻只能运行一个线程, 如果有多个线程处于可运行状态想,需要排队等待CPU 资源, 此时线程将进队等候, CPU资源分配是根据“先到先服务” 的原则确定线程排队顺序的。

Java为了使有些线程可以提前得到服务, 给线程设置了优先级,在单个 CPU上运行多线程时采用线程队列技术 ,Java虚拟机支持固定优先级队列,一个线程的执行顺序取决于线程的优先级。 高优先的线程大概率比低优先的线程优先获得CPU资源,但不代表一定以优先级低的线程优先执行

线程在创建时,继承了父类的优先级, 线程创建后,还可以在任何时刻调用 setPriority 方法改变线程的优先级。 优先级为 1 ~ 10. Thread 定义了其中 3 个常数:
(1) MAX_PRIORITY, 最大优先级(值为10)。
(2)MIN_PRIORITY,最小优先级(值为1)。
(3)NORM_PRIORITY,默认优先级,(值为5),注意是Java主线程默认的优先级是 5

package Xg27;class Thread2 extends Thread{public void run() {for (int i = 0; i< 1000000; i ++ );System.out.println(getName() + "线程的优先级是" + getPriority() + "已计算完毕!");}
}public class exp9_2{public static void main(String args[]) {Thread2[] t = new Thread2[4];for (int i = 0; i<4; i++) {t[i] = new Thread2();}t[3].setPriority(10);t[1].setPriority(1);for(int i = 0 ;i < 4;i++) {t[i].start();}}
}

运行结果:

Thread-2线程的优先级是5已计算完毕!
Thread-1线程的优先级是1已计算完毕!
Thread-3线程的优先级是10已计算完毕!
Thread-0线程的优先级是5已计算完毕!

可见并不是由高优先级就会最先执行。

控制线程的状态

(1)线程的启动——“可执行”状态

一个新的线程被创建后处于初始状态,实际上并没有立刻进入运行状态,而是处理就绪状态,当轮到这个线程执行的时候,即进入“可执行”状态,开始执行线程 run() 方法中的代码。

执行 run() 方法是通过调用 Thread类中的 start () 方法来实现的。

调用 start() 方法启动线程的 run() 方法不同于一般的调用方法,一般方法必须等到方法执行完毕才能够返回, 调用 start() 方法告诉系统该线程准备就绪可以启动 run() 方法后, 就返回, 并继续执行调用 start( )方法下面的语句, 这时 run()方法可能还在运行,这样就实现了多任务操作。

(2)线程的挂起——“非可执行”状态

线程挂起就是使线程进入非可执行状态,线程挂起后 CPU 不会分给线程时间段, 线程暂停运行, 通过重新唤醒线程可以使之恢复运行。 这个过程在外表看来什么也没有发生过, 只是线程很慢的执行一条指令。

线程进入“非可执行” 状态即挂起的原因如下:
(1) 线程休眠。 通过调用 sleep() 方法是线程进入休眠状态, 线程在指定时间内暂停运行,暂停的时间有 sleep() 给定的毫秒数决定。执行休眠方法后,如果任何一个线程中断了当前的休眠, sleep() 将抛出 InterruptedException 异常对象, 所以在使用sleep() 方法时,必须捕获该异常。

(2)线程插入。 通过调用 join() 方法使当前线程挂起,如果线程A调用 线程 B的 join () 方法,那么线程A 将被挂起,直到线程 B 执行完毕。

(3)线程等待。 通过调用 wait() 方法使线程挂起, 直到线程得到了 notify() 和 notifyAll() 消息,线程才会进入“可执行状态”。

  • 方法1:通过 thread.wait(1000); 给定线程挂起等待的时间。
  • 方法2: 通过thread.wait() 实现挂起, 通过 thread.notify() 或 notifyAll() 唤醒执行。

wait() ,notify() , notifyAll() 不同与其他线程方法,它们是 java.lang.Object 类的一部分,而 Object 类是所有类的父类, 所以这 3 个方法会自动被所有类继承, 它们是 final 类,所以无法重新定义。

(3)确定线程的状态
一般情况下无法确定要给线程的运行状态,对于这些处于未知状态的线程,可以通过isAlive() 方法来确定一个线程是否仍处在活动状态, 对于一个已开始运行但是还没有完成任务的线程, 这个方法返回值是 true 。但处于活动状态的线程不一定正在运行。

(4)结束线程

(1)自然消亡,一个线程从 run( ) 方法的结尾处返回, 自然消亡且不能再被运行。
(2)强制死亡,调用 Thread类中的 stop() 方法强制停止, 不过该方法已经被废弃。最好提供一个方式让线程可以完成 run() 的流程,即让它自然死亡。

(4)后台线程
即 Daemon 线程,它是一个再后台执行服务的线程。
例如,操作系统中的隐藏线程和Java语言中的垃圾自动回收线程等,如果所有的非后台线程都结束了,则后台线程也会自动终止。

可以使用 thread.setDaemon(boolean on) 方法来设置一个后台线程,参数 on 为 true ,则将该线程标记为后台线程。
但是有一点值得注意:必须在线程启动之前调用 setDaemon () 方法, 这样才能将这个线程设置为后台线程, 可以使用 thread.isDaemon() 方法来判断线程是否是后台线程。

Java的线程同步机制与应用模型

之前所讲的线程它们都是独立的,而且异步执行,也就是说每个线程都包含了运行时所需的数据和方法,不要外部资源,也不用关心其他线程的状态和行为。

但有时一些同时运行的线程需要 共享数据 , 例如两个线程同时存取一个数据,其中一个对数据进行了修改,另外一个线程使用的是原来的数据,这就带来了数据不一致问题,因此,编程时必须考虑其他线程的状态和行为,以解决资源共享问题:

—— 同步机制

共享资源一般是文件、输入/输出端口或打印机。
为了避免多线程共享资源发生冲突的情况,只要在线程使用资源时给该资源上一把锁就可以了,

 当有线程使用资源时, 此时资源的状态: 正在使用中。  就像银行的排号系统,保证了每个窗口仅有一个客户在办理业务。

访问资源的第一个线程为资源上锁, 其他线程若想使用这个资源必须等到锁解除为止,锁揭开的同时另一个线程使用该资源并为这个资源上锁。

java的线程同步机制:所谓同步机制指的是两个线程同时操作一个对象时为保持 对象数据的统一性和整体性,通过添加 synchronized(同步化)关键字来锁定对象,执行单一线程,使得其他线程不能同时调用同一个对象。

同步方式有两种形式,即 同步方法同步代码块

1、 同步方法
同步方法将访问这个资源的方法都标记为 synchronized, 这样在需要调用这个方法的线程执行完之前, 其他调用该方法的线程都会被阻塞。 可以使用如下代码声明一个同步方法。

synchronized void sum(){……};  定义取和的同步方法
synchronized void max()(……);  定义取最大值的同步方法

2、 同步代码块

Java语言中同步的设定不只应用于同步方法, 也可以设置程序的某个代码段块为同步区域, 可以使用如下代码声明一个代码块。

synchronized(someobject){   //someobject代表当前对象,同步的作用区域是 synchronized 关键字后大括号以内的部分,在程序执行到 synchronized 设定的同步化区块时锁定当前对象, 这样就没有其他线程可以执行这个被同步化的区块了。
……}

使用多线程应注意的问题

1 、 防止线程死锁

因为线程可以阻塞,并且具有同步控制机制可以防止其他线程在还锁还没有释放的情况下访问这个对象,这时就产生了矛盾,比如: 线程 A 在等待线程 B ,而线程 B 又在等待线程 A , 这样就造成了死锁。

一般造成死锁必须同时满足一下四个条件。
(1)互斥条件:线程使用的资源必须至少有一个是不能共享的。
(2)请求与保持条件: 至少有一个线程必须持有一个资源并且正在等待获取一个当前被其他线程持有的资源。
(3)非剥夺条件: 分配的资源不能从相应的线程中被强制剥夺。
(4)循环等待条件:第一个线程等待其他线程,后者又在等待一个线程。

如果要防止死锁,只需破坏其中一个条件即可。

2 、 使用多线程的代价

不是所有的任务都需要多线程,某些任务可以使用多线程,例如数据计算,数据查询以及输入的获得。因为这些任务通常都被认为是后台任务,不直接与用户打交道,在Java语言程序设计中,动态效果的程序会使用多线程, 例如动画的播放、动态的字幕等。

任何事情都不是完美的,多线程也不例外,在程序中使用多线程是有代价的,它会对系统产生如下影响:

(1)线程需要占用内存、
(2)线程过多,会消耗大量CPU时间来跟踪线程。
(3)必须考虑多线程同时访问共享资源的问题,如果没有协调好,就会产生令人意想不到的问题,例如死锁和资源竞争。
(4)因为同一个任务的所有线程都共享相同的地址空间,并共享任务的全局变量,所以程序也必须考虑多线程同时访问全局变量的问题。

多线程机制(四)线程的优先级与状态相关推荐

  1. 多线程技术(四)线程的优先级

    线程是根据其优先级来调度的,每个线程都有特定的优先级.每个线程在创建时其优先级为: ThreadPriority.Normal 线程的优先级定义为ThreadPriority枚举类型,如下表: 例题3 ...

  2. JAVA中的多线程(八):线程的优先级和yield方法

    JAVA中的多线程(八):线程的优先级和yield方法 优先级代表着抢资源的频率 所有线程默认优先级是5 yield()临时释放线程的执行权 1 class Demo implements Runna ...

  3. java 多线程4: java线程的优先级

    Java线程的优先级取值范围是1 (Thread.MIN_PRIORITY ) 到 10 (Thread.MAX_PRIORITY ).如果没有设置, 线程默认的优先级是NORM_PRIORITY.这 ...

  4. java基础提升(二):多线程、线程安全、线程状态、等待唤醒机制、线程池

    目录 一. 多线程 1.1并发与并行 1.2 线程与进程 1.3 创建线程类 1.3.1 方式一:继承Thread类 1.3.2 方式二:实现Runnable接口 1.3.3 Thread和Runna ...

  5. java 禁止使用多线程_Java多线程(四)-线程状态的转换 - Java 技术驿站-Java 技术驿站...

    一.线程状态 线程的状态转换是线程控制的基础.线程状态总的可分为五大状态:分别是生.死.可运行.运行.等待/阻塞.用一个图来描述如下: 1.新状态:线程对象已经创建,还没有在其上调用start()方法 ...

  6. 学习java的第四十天,线程的优先级、守护线程、线程同步机制、死锁

    一.线程的优先级(priority) Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行. 线程的优先级用数字表示,范围1~10 Thr ...

  7. Java多线程学习四:共有哪 3 类线程安全问题

    我们在实际开发中经常会遇到线程不安全的情况,那么一共有哪 3 种典型的线程安全问题呢? 运行结果错误: 发布和初始化导致线程安全问题: 活跃性问题. 运行结果错误 来看多线程同时操作一个变量导致的运行 ...

  8. Java多线程(四)线程锁

    6.锁 由于多个线程是共同占有所属进程的资源和地址空间的,那么就会存在一个问题: 如果多个线程要同时访问某个资源,怎么处理? 在Java并发编程中,经常遇到多个线程访问同一个 共享资源 ,这时候作为开 ...

  9. java的多线程机制_Java多线程开发(一)| 基本的线程机制

    0. 前言 Java 为了实现跨平台,在语言层面上实现了多线程.我们只需要熟悉 Java 这一套多线程机制就行了,比 C/C++ 要容易多了. 1. 定义任务 我们编写程序,最终是为了完成特定的任务. ...

最新文章

  1. 触摸矫正+android,android触摸矫正解方程
  2. 一文看懂深度学习发展史和常见26个模型
  3. 炫界 (587) -(牛一邓丽君音)_50音起源 for mac(日语五十音学习软件)
  4. JS高级-自执行函数-垃圾回收机制及内存管理
  5. 云虚拟主机和传统虚拟主机的区别?
  6. 排序算法(四)--谢尔排序(缩小增量排序)
  7. ad网络标号怎么批量设置_网络打印机怎么设置 网络打印机安装方法【详细步骤】...
  8. 使用UInput模拟系统键盘鼠标动作 UInput driver分析
  9. 中国移动MM7API开发问题
  10. 21家科技巨头名字背后的故事|
  11. 布兰迪斯大学计算机美国大学排名,美国大学排名 布兰迪斯大学排名汇总
  12. 如何删除双系统中的ubuntu
  13. AD软件自动添加原理图标注
  14. 王者荣耀战力查询小程序源码下载-支持安卓ios微信和QQ战力查询支持打包成APP
  15. SpringbootApi接口学习笔记
  16. 手机控制云服务器文件,手机控制云服务器的app
  17. cadence SPB16.6原理图库(.olb)集合的库内容列表1
  18. 10分钟go crawler colly从入门到精通
  19. 刚安装的谷歌浏览器搜索异常
  20. c语言单片机与plc通讯,用c51实现单片机和plc之间通讯实例

热门文章

  1. bind和unbind事件
  2. 灵遁者:我特别能理解很多人对某东西,某事物上瘾或者着迷
  3. 潘石屹学python-周鸿祎调侃潘石屹学python:他写的估计一百行里有十个漏洞
  4. miui什么时候上android q,MIUI官方公布小米手机升级Android Q计划
  5. 《SpringSecurityOauth2》SpringOauth2.0 中 scope 和 authorities的区别
  6. 【架构设计】服务治理理论(一)
  7. MFC 获取计算机的IP地址误区 10049 WSAEADDRNOTAVAI
  8. 22事务(TCL) ——MySQL
  9. Linux Shell脚本编程--awk命令详解
  10. 利用NLTK做中英文分词