当前位置: 首页 > news >正文

网站开发学那个语言比较好关键时刻

网站开发学那个语言比较好,关键时刻,dw网页制作怎么改字体大小,李沧网站建设公司更多内容,欢迎关注微信公众号:全菜工程师小辉~线程的生命周期转换线程的生命周期新建状态(New):新建一个线程对象。就绪/可运行状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运…

更多内容,欢迎关注微信公众号:全菜工程师小辉~

线程的生命周期转换

59f927ebd6b3caf384f4799b47598b5c.png

线程的生命周期

  1. 新建状态(New):新建一个线程对象。
  2. 就绪/可运行状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
  3. 运行状态(Running):就绪状态的线程获得CPU并执行程序代码。
  4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
  5. 等待阻塞:运行的线程执行wait方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
  6. 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
  7. 其他阻塞:运行的线程执行sleep或join方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep的状态超时、join等待线程终止或者超时、以及I/O处理完毕时,线程重新转入就绪状态。
  8. 死亡状态(Dead):线程执行完成或者因异常退出run方法,该线程结束生命周期。

wait()与notify()

  • wait():使调用该方法的线程释放共享资源锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
  • wait(long):超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。
  • wait(long,int):对于超时时间更细力度的控制,单位为纳秒。
  • notify():随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。
  • notifyAll():使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM虚拟机的实现。

什么是等待/通知机制

通俗来讲:

等待/通知机制在我们生活中很常见,一个形象的例子就是厨师和服务员之间就存在等待/通知机制。

  • 厨师做完一道菜的时间是不确定的,所以菜到服务员手中的时间也是不确定的。
  • 服务员就需要去“等待(wait)”。
  • 厨师把菜做完之后,按一下铃进行“通知(nofity)”。
  • 服务员听到铃声之后就知道菜做好了,就可以去端菜了。

使用专业术语讲:

等待/通知机制,是指线程A调用了对象O的wait()方法进入等待状态,而线程B调用了对象O的notify()/notifyAll()方法,线程A收到通知后退出等待队列,进入可运行状态,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()方法和notify()/notifyAll()方法的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。

多线程轮流打印代码示例

通过一道面试题就能完全明白wait/notify机制。

问题:写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印结果为12A34B...5152Z

class Print { private int flag = 1;//信号量。当值为1时打印数字,当值为2时打印字母 private int count = 1; public synchronized void printNum() { if (flag != 1) { //打印数字 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print(2 * count - 1); System.out.print(2 * count); flag = 2; notify(); } public synchronized void printChar() { if (flag != 2) { //打印字母 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print((char) (count - 1 + 'A')); count++;//当一轮循环打印完之后,计数器加1 flag = 1; notify(); }}public class Test { public static void main(String[] args) { Print print = new Print(); new Thread(() -> { for (int i = 0; i < 26; i++) { print.printNum(); } }).start(); new Thread(() -> { for (int i = 0; i < 26; i++) { print.printChar(); } }).start(); }}

FAQ

wait、notify/notifyAll和sleep的区别与联系:

  1. 前三个方法是Object的本地final方法,sleep方法是Thead类的静态方法。
  2. wait使当前线程阻塞,前提是必须先获得锁,所以只能在synchronized锁范围内里使用wait、notify/notifyAll方法,而sleep可以在任何地方使用。
  3. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。
  4. notify和wait的顺序不能错,如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的。

notify和notifyAll的区别

  • notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
  • notifyAll会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll方法。

sleep和wait的区别

  1. 当线程执行sleep方法时,不会释放当前的锁(如果当前线程进入了同步锁),也不会让出CPU。sleep(milliseconds)可以用指定时间使它自动唤醒过来,如果时间不到只能调用interrupt方法强行打断。
  2. 当线程执行wait方法时,会释放当前的锁,然后让出CPU,进入等待状态。只有当notify/notifyAll被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized代码块的代码或是中途遇到wait() ,再次释放锁。

Thread.Sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”

notify/notifyAll的执行只是唤醒沉睡的线程,而不会立即释放锁,必须执行完notify()方法所在的synchronized代码块后才释放。所以在编程中,尽量在使用了notify/notifyAll()后立即退出临界区。

改变线程优先级

每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会。每个线程默认的优先级都与创建它的父线程的优先级相同。Thread类提供了setPriority(int newPriority)来设置指定线程的优先级,提供了getPriority()来返回指定线程的优先级。

JAVA提供了10个优先级级别,但这些优先级需要操作系统支持。不同的操作系统上的优先级并不相同,而且也不能很好的和JAVA的10个优先级对应,比如:Windows 2000仅提供了7个优先级。因此,写代码的时候应该尽量避免直接为线程指定优先级,而应该使用MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY这三个静态常量来设置优先级,这样才能保证程序有最好的可移植性。

一个线程两次调用start方法会出现什么情况?

Java的线程是不允许启动两次的,第二次调用必然会抛出IllegalThreadStateException,这是一种运行时异常。

park()与unpark()

concurrent包是基于AQS(AbstractQueuedSynchronizer)框架的,AQS框架借助于两个类:

  1. Unsafe(提供CAS操作)
  2. LockSupport(提供park/unpark操作)

LockSupport.park()和LockSupport.unpark(Thread thread)调用的是Unsafe中的native代码。

有关AQS,可以查看笔者之前的博客,快速了解基于AQS实现的Java并发工具类

park与unpark的特点

  1. park/unpark的设计原理核心是“许可”(permit):park是等待一个许可,unpark是为某线程提供一个许可。permit不能叠加,也就是说permit的个数要么是0,要么是1。也就是不管连续调用多少次unpark,permit也是1个。线程调用一次park就会消耗掉permit,再一次调用park又会阻塞住。如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上。
  2. unpark可以先于park调用。在使用park和unpark的时候可以不用担心park的时序问题造成死锁。相比之下,wait/notify存在时序问题,wait必须在notify调用之前调用,否则虽然另一个线程调用了notify,但是由于在wait之前调用了,wait感知不到,就造成wait永远在阻塞。
  3. park和unpark调用的时候不需要获取同步锁。

park与unpark的优点

与Object类的wait/notify机制相比,park/unpark有两个优点:

  1. 以thread为操作对象更符合阻塞线程的直观定义。
  2. 操作更精准,可以准确地唤醒某一个线程(notify随机唤醒一个线程,notifyAll唤醒所有等待的线程),增加了灵活性。

底层实现原理

在Linux系统下,是用的Posix线程库pthread中的mutex(互斥量),condition(条件变量)来实现的。

mutex和condition保护了一个_counter的变量,当park时,这个变量被设置为0,当unpark时,这个变量被设置为1。

更多内容,欢迎关注微信公众号:全菜工程师小辉~

http://www.lbrq.cn/news/2741491.html

相关文章:

  • 绵阳公司网站制作公司seo新手快速入门
  • 头条号链接其他网站怎么做广州企业网站建设
  • 河间做网站seo优化必备技巧
  • 网站创建方法手机关键词seo排名优化
  • 网站制作方案策划书长春建站程序
  • 一个网络空间如何做两个网站正规seo排名公司
  • 哪个网站可以找题目给小孩做seo站外推广有哪些
  • 做 专而精 的网站制作网站的工具
  • 做好的网站怎么优化金花站长工具
  • 网页设计的网站推荐如何在百度发广告推广
  • 旋风加速官网下载seo系统培训哪家好
  • 潍坊哪家网站制作公司好搜索引擎调词工具
  • 公司做网站怎么收费如何推广公司
  • 网站建设的编程广州网站推广服务
  • 济南手机建站价格搜索引擎优化自然排名的优点
  • 公司如何申请域名网站seo设计方案案例
  • 西安做网站电话医院线上预约
  • 旅游网站毕业论文seo智能优化软件
  • 怎样建立网站的快捷方式河南郑州网站顾问
  • 厦门 微网站建设公司培训机构网站模板
  • 如何设计一个网站没灵感百度ai人工智能
  • 静态网站做淘宝客爱站工具包的模块有哪些
  • 全国工厂的网站建设seo软件优化
  • 怎么做网站上的销售代北京网站排名推广
  • 江苏建设部官方网站优化关键词的正确方法
  • 2012系统 做网站百度做网站
  • 福州外文网站建设分销渠道
  • 自建网站教程视频h5页面制作平台
  • wordpress链接域名seo是什么意思电商
  • 做公众号推送的网站广告投放平台系统
  • 深入了解 swap:作用、局限与分区建立
  • 初识CNN02——认识CNN2
  • 深入解析五大通信协议:TCP、UDP、HTTP_HTTPS、WebSocket与GRPC
  • 神经网络 小土堆pytorch记录
  • DevEco Studio 6.0.0 元服务页面跳转失败
  • Spring中存在两个相同的Bean是否会报错?