查漏补缺(长期更新)

前言

Java的部分有基础、设计模式、IO、NIO、多线程,之后有时间还会把集合这部分补上去,这么多内容里面,难免有一些知识点遗漏,本文主要是讲解这些遗漏的知识点。这些知识点,不是特别大的难点,所以没有必要专门写一篇文章讲解;但是这些知识点,也不是一两句话就说得清楚的,所以放在这里。本文和前面的代码优化、类继承接口实现一样,也是一篇长期更新的文章,只要想到有遗漏的知识点,就会随时更新此文。

Thread.sleep(XXX)方法消耗CPU吗?

这个知识点是我之前认识一直有错误的一个知识点,在我以前的认识里面,我一直认为Thread.sleep(1000)的这一秒钟的时间内,线程的休眠是一直占用着CPU的时间片休眠的,查看了资料和仔细思考之后发现不是。Thread.sleep(1000)的意思是:代码执行到这儿,1秒钟之内我休息一下,就不参与CPU竞争了,1秒钟之后我再过来参与CPU竞争。

说到这儿,就要顺便再提sleep和wait的区别了,JDK源码提供给我们的注释是非常严谨的:

 1 /**
 2  * Causes the currently executing thread to sleep (temporarily cease
 3  * execution) for the specified number of milliseconds, subject to
 4  * the precision and accuracy of system timers and schedulers. The thread
 5  * does not lose ownership of any monitors.
 6  *
 7  * @param      millis   the length of time to sleep in milliseconds.
 8  * @exception  InterruptedException if any thread has interrupted
 9  *             the current thread.  The <i>interrupted status</i> of the
10  *             current thread is cleared when this exception is thrown.
11  * @see        Object#notify()
12  */
13 public static native void sleep(long millis) throws InterruptedException;
 1 /**
 2  * Causes the current thread to wait until another thread invokes the
 3  * {@link java.lang.Object#notify()} method or the
 4  * {@link java.lang.Object#notifyAll()} method for this object.
 5  * In other words, this method behaves exactly as if it simply
 6  * performs the call <tt>wait(0)</tt>.
 7  * <p>
 8  * The current thread must own this object‘s monitor. The thread
 9  * releases ownership of this monitor and waits until another thread
10    ...
11  */
12 public final void wait() throws InterruptedException {
13 wait(0);
14 }

看sleep方法的第4、第5行,"The thread does not lose ownership of any monitors"

看wait方法的第8、第9行,"The thread releases ownership of this monitor"

所以二者的差别就来了,差别就在"monitor"也就是监视器上,sleep和wait方法的执行都会释放CPU资源,但是sleep方法不会释放掉监视器的所有权,而wait方法会释放掉监视器的所有权。所谓监视器,就是假如sleep方法和wait方法处于同步方法/同步方法块中,它们所持有的对象锁

Thread.sleep(0)的作用

讲这个问题,要先讲一下两种线程调度的方法,周志明老师的《深入理解Java虚拟机:JVM高级特性与最佳实践》第12章第4节对这块内容有比较清楚的解释。

线程调度指的是系统为线程分配处理器使用权的过程,主要调度方式有两种:协同式线程调度抢占式线程调度

1、协同式线程调度

使用协同式线程调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上。这种调度方式最大的好处就是实现简单,而且由于线程要把自己的事情干完了才会进行线程切换,切换操作对线程自己是可知的,所以没有什么线程同步问题。不过协同式线程调度的坏处也很明显:线程执行时间不受控制。如果一个线程编写有问题,一直不告诉系统进行线程切换,那么程序便会一直阻塞在那儿。所以这种方式非常不稳定,一个线程坚持不让出CPU执行时间就可能会导致整个系统崩溃。

2、抢占式线程调度

抢占式线程调度方式是由系统来分配执行时间的,线程切换不由线程本身来决定。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题。

很明显Java采取的是抢占式调度方式。Java的线程是通过映射到系统的原生线程上实现的,在某个线程挂起或者分给它的CPU时间片到了之后,操作系统会根据线程优先级、线程饥饿程度等算出一个总的优先级出来,然后再挑选一个线程,分给它时间片。

讲了这么多,回到我们的主题上,我总结两点:

1、CPU分出来的时间片,可以竞争的线程都是会去竞争获取的

2、调用了Thread.sleep(XXX)方法的线程,意味着在XXX毫秒的时间内,该线程不参与CPU时间片的竞争

那么Thread.sleep(0)是干什么用的呢?它的作用就是:强制操作系统触发一次CPU计算优先级并分配时间片的动作。比如线程A获得了5毫秒的CPU执行时间,如果在执行了2毫秒的时候遇到了Thread.sleep(0)语句,那么后面的3毫秒的时间片就不运行了,操作系统重新计算一次优先级,并分配下一个CPU时间片给哪个线程。

这个小细节对于系统运行是有好处的:

1、避免了某一线程长时间占用CPU资源,我们知道在Java中比如开了两个非守护线程,线程优先级为10的线程A与线程优先级为5的线程B同时执行,这意味着操作系统基本上绝大多数时间都在运行线程A,基本不会把CPU控制权交给线程B

2、避免了系统假死

3、让线程有比较平均的机会获得CPU资源

不过Thread.sleep(0)虽然好,但是不要去滥用它。一个系统CPU占用率高是好事情,这意味着CPU在做事情,没有闲着。但是CPU占用率高还得保证CPU做的事情是应该做的事情,比如CPU占用率高,但是在死循环,有意义吗?这就是代码写得有问题。Thread.sleep(0)也一样,这句语句触发了操作系统计算优先级、分配时间片的动作,势必占用CPU的时间,如果在很多线程里面都滥用这个方法的话,CPU使用率是上去了,但大多数时间做的都是无意义的事情。我认为这个动作的目的更多是为了优化系统,而不是代码必须执行的一部分

时间: 2024-12-21 07:39:42

查漏补缺(长期更新)的相关文章

近来的java小总结(2.1):类的知识的查漏补缺

首先,我是一名新手,所以,要带着批判的眼光来看下面的文章   这篇文章说了些什么? 这文章是我近来8.6号来在编程思想上打的代码,从0~200页的源码接近到在这里,下文正是总结这0~200页的的知识,涉及到接口,内部类.初始化,数值计算的一些细节.此文章不会一下子写完,可能隔一天可能再补下来.因为代码确实有点多.. 注意 1 我的注释不一定正确(不过各小标题和代码一定是正确的,因为是书本上的原话,但是注释不一定正确),如果你确信我的内容的话,你可能会损失很大,因为我只是个菜鸟,我只是来补救一些知

近来的java小总结(2.2):类的知识的查漏补缺

1 首先,我是一名新手,所以,要带着批判的眼光来看下面的文章   这篇文章说了些什么? 这文章是我近来8.6号来在编程思想上打的代码,从0~200页的源码接近到在这里,下文正是总结这0~200页的的知识,涉及到接口,内部类.初始化,数值计算的一些细节.此文章不会一下子写完,可能隔一天可能再补下来.因为代码确实有点多.. 注意 1 我的注释不一定正确(不过各小标题和代码一定是正确的,因为是书本上的原话,但是注释不一定正确),如果你确信我的内容的话,你可能会损失很大,因为我只是个菜鸟,我只是来补救一

自家用的java小总结(2.4):类的知识的查漏补缺(内部类)

1 2      首先,这是一篇自己用的文章,不对读者承担任何责任,所以,要带着批判的眼光来看下面的文章   1 发现了,得加上输出结果,怕自己出错,~~   这篇文章说了些什么? 这文章是我近来8.6号来在编程思想上打的代码,从0~200页的源码接近到在这里,下文正是总结这0~200页的的知识,涉及到接口,内部类.初始化,数值计算的一些细节.此文章不会一下子写完,可能隔一天可能再补下来.因为代码确实有点多.. 注意 1 我的注释不一定正确(不过各小标题和代码一定是正确的,因为是书本上的原话,但

Entity Framework 查漏补缺 (一)

明确EF建立的数据库和对象之间的关系 EF也是一种ORM技术框架, 将对象模型和关系型数据库的数据结构对应起来,开发人员不在利用sql去操作数据相关结构和数据.以下是EF建立的数据库和对象之间关系 关系数据库 对象 数据库 DbContext类 表 DbContext中的DbSet<实体类名> 表间的关联 实体类之间的关联 字段 实体类的公有属性 单条数据 单个实体类的对象 约束(主键.外键默认值) 实体类中的特性 了解EDM( 实体数据模型) EF使用概念模型. 映射和存储模型.三个模型来描

2019/5/12 查漏补缺

目录 2019/5/12 查漏补缺 数据类型分为两大类:基本类型和引用类型: java中类的继承关系 关于接口 重载和重写 静态变量 java中的关键字和保留字 数据库操作 实现数据库收回部分权限的操作 关于数据库错误类型 SQL四种语言: 数据库常见的四种故障 数据库设计六个阶段: Java的异常分为两种 外模式,内模式 数据库范式 语句null的书写 2019/5/12 查漏补缺 数据类型分为两大类:基本类型和引用类型: 基本类型只能保存一些常量数据,引用类型除了可以保存数据,还能提供操作这

查漏补缺——java多态

---恢复内容开始--- 刚学完java,开始了查漏补缺阶段阶段,为了巩固自己的知识和为别人提供一些微末的帮助决定开通博客,求各位大牛们指出我的不足,不要吝惜言语,也希望我的总结可以对别人有帮助,对自己对他人负责. 开始正文:术语多态:可以定义为“有多种形态”,多态引用是一个一个在不同时刻可以指向不同类型对象的引用变量.通过多态引用可以调用不同的具体的方法. 类方法的多态性的实现有两种方式: 1:方法重载:可以声明多个同名但是参数不同(个数.类型和顺序)的方法.注意呵呵重载方法只能声明在一个类里

java知识查漏补缺

一.重写(override)和重载(overload)的区别 二者除了名字相似,其实没什么联系 范围不同:重写发生在同一个类的不同方法之间.重载发生在父类和子类自荐. 前提: 重写要求:方法名相同,参数列表不同,对于返回值类型不要求相同. 重载要求:方法名形同,参数列表也相同.重载是实现多态的关键,注意如果父类中的方法是private类型,那么子类中对应方法不算重载,而相当于是定义了一个新方法. 二.final的用法 修饰类:该类不能被继承 修饰方法:该方法不能被重写 修饰属性:该属性初始化后不

查漏补缺

查漏补缺[1].this语句:this语句用于构造函数之间进行相互调用.this语句只能定义在构造函数的第一行,因为初始化要先执行.[2].对象的初始化过程 Person p =new Person("hei",10); 1.因为new用到了Person.class,所以先找到Person.class文件加载到内存中 2.执行类中的静态代码块,如果有的话,给Person.class类进行初始化 3.在堆内存中开辟空间,分配内存地址 4.在堆内存中建立对象的特有属性,并进行默认初始化 5

《CSS权威指南》基础复习+查漏补缺

前几天被朋友问到几个CSS问题,讲道理么,接触CSS是从大一开始的,也算有3年半了,总是觉得自己对css算是熟悉的了.然而还是被几个问题弄的"一脸懵逼"... 然后又是刚入职新公司,事情不算多,于是拿起<CSS权威指南>进行"基础学习"+"查漏补缺",本篇文章主要是总结了些自己认为CSS中值的注意的几个知识点(本文知识点仅限本书范围内,若要讲CSS全部样式,那本兽还是选择慢慢懵逼去~). 选择器 这里要说明的是类选择器的嵌套选择与多类

hibernate查漏补缺2

Hibernate对象状态 瞬时(transient):由new操作符创建,且尚未Hibernate Session关联.瞬时对象不会被持久化到数据库,也不会被赋予持久化标识. 持久(persistent):持久化的实例在数据库中有对应的记录,并拥有一个持久化标识. 持久化的实例可能是刚被保存,或刚被加载的,无论哪一种,它都只存在于相关联的Session作用范围内.这点很重要.Hibernate会检测处于持久化状态的对象的任何变动,在当前操作单元执行完毕时,将对对象数据与数据库同步. 脱管(de