java编程对cpu的实际需求有多少

一、MRV1有哪些不足

1)可扩展性(对于变化的应付能力)
a) JobTracker失效会多事集群中全部的运行做业,用户需手动从新提交和恢复工做流
3)对不一样编程模型的支持

二、描述Yarn执行一个任务的过程?

四、提交任务时,如何指定Spark Application的运行模式?

20、jvm怎么调优的,介绍你的Spark JVM调优经验?

参考梅峰谷博文 《Spark 应用经验与程序调优》设置合理的 JVM 部分

2一、jvm结构?堆里面几个区?

1)JVM 内存区域分为方法去、虚拟机栈、本地方法栈、堆、程序计数器方法区: 也称" " 永久代 ” 、 “ 非堆 ”, 它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域
虚拟机栈:描述的是 Java 方法执行的内存模型:每一个方法被执行的时候 都会建立一个“栈帧”用于存储局部变量表(包括参数)、操做栈、方法出口等信息
本地方法栈:与虚拟机栈基本相似,区别在于虚拟机栈为虚拟机执行的 java 方法服务,而本地方法栈则是为 Native 方法服务
堆:也叫作 java 堆、GC 堆是 java 虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在 JVM 启动时建立。
程序计数器:是最小的一块内存区域,它的做用是当前线程所执行的字节码的行号指示器。

b.新生代能够划分为三个区,Eden 区(存放新生对象),两个幸存区(From Survivor 和To Survivor)(存放每次垃圾回收后存活的对象);

d.JVM 垃圾回收机制采用“分代收集”:新生代采用复制算法,老年代采用标记清理算法

2二、怎么用spark作数据清洗

从 2 方面介绍和回答,一是说下 partition 是什么玩意,二是说下 partition 如何建的
1)spark 中的 partion 是弹性分布式数据集 RDD 的最小单元,RDD 是由分布在各个节点上的partion 组成的。partion 是指的 spark 在计算过程当中,生成的数据在计算空间内最小单元,同一份数据(RDD)的 partion 大小不一,数量不定,是根据 application 里的算子和最初读入的数据分块数量决定的,这也是为何叫“弹性分布式”数据集的缘由之一。Partition不会根据文件的偏移量来截取的(好比有 3 个 Partition,1 个是头多少 M 的数据,1 个是中间多少 M 的数据,1 个是尾部多少 M 的数据),而是从一个原文件这个大的集合里根据某种计算规则抽取符合的数据来造成一个 Partition 的

2六、画图,画Spark的工做模式,部署分布架构图

参考梅峰谷博文《【Spark 你妈喊你回家吃饭-11】Spark 基本概念和运行模式》

2七、画图,画图讲解spark工做流程。以及在集群上和各个角色的对应关系。

参考梅峰谷博文《【Spark 你妈喊你回家吃饭-13】Spark 计算引擎剖析》

2八、java自带有哪几种线程池。

建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。这种类型的线程池特色是:
一、工做线程的建立数量几乎没有限制(其实也有限制的,数目为 Interger. MAX_VALUE),这样可灵活的往线程池中添加线程。、
二、若是长时间没有往线程池中提交任务,即若是工做线程空闲了指定的时间(默认为 1分钟),则该工做线程将自动终止。终止后,若是你又提交了新的任务,则线程池从新建立一个工做线程。
三、在使用 CachedThreadPool 时,必定要注意控制任务的数量,不然,因为大量线程同时运行,颇有会形成系统瘫痪。

建立一个指定工做线程数量的线程池。每当提交一个任务就建立一个工做线程,若是工做线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。FixedThreadPool 是一个典型且优秀的线程池,它具备线程池提升程序效率和节省建立线程时所耗的开销的优势。可是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工做线程,还会占用必定的系统资源。

建立一个单线程化的 Executor,即只建立惟一的工做者线程来执行任务,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。若是这个线程异常结束,会有另外一个取代它,保证顺序执行。单工做线程最大的特色是可保证顺序地执行各个任务,而且在任意给定的时间不会有多个线程是活动的。

建立一个定长的线程池,并且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。延迟 3 秒执行.

2九、画图,讲讲shuffle的过程。那你怎么在编程的时候注意避免这些性能问题?

参考梅峰谷博文《【Spark 你妈喊你回家吃饭-13】Spark 计算引擎剖析》

参考王家林的视频教程《38-BlockManager 架构原理、运行流程图和源码解密》

一、kafka收集数据的原理?

二、讲讲列式存储的 parquet文件底层格式?

六、列举Spark中常见的端口,分别有什么功能?

八、Spark官网中,你经常使用哪几个模块?

九、你有见过哪些缘由致使的数据倾斜,怎么解决?

十、简要描述宽依赖窄依赖以及各自的特色?

十一、yarn的原理?

十二、BlockManager怎么管理硬盘和内存的?

1三、哪些算子操做涉及到shuffle1

1四、看过源码? 你熟悉哪几个部分的源码?

1六、Spark如何处理结构化数据,Spark如何处理非结构话数据?

1七、Spark性能优化主要有哪些手段?

1八、简要描述Spark分布式集群搭建的步骤?

1九、对于Spark你以为他对于现有大数据的现状的优点和劣势在哪里?

20、对于算法是否进行过自主的研究设计?

2一、简要描述你了解的一些数据挖掘算法与内容 

2四、spark 如何防止内存溢出 ?

2五、简述hadoop实现join的及各类方式?

2七、列举你熟悉的内存系统,各自的优缺点?

2九、函数式编程特色?

}

希望通过这种连环炮的方式,让大家更好吸收知识点,同时也是面试中出现频率非常高。

废话不多说,直奔主题。

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要,那么用十个线程完成该任务只需。

一个进程是一个独立()的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

有两种创建线程的方法:一是实现接口,然后将它传递给的构造函数,创建一个对象;二是直接继承类。

这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用接口来实现线程,问题是,那个方法更好呢?什么情况下使用它?

这个问题很容易回答,如果你知道不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用接口好了。更多详细信息请点击这里。

方法被用来启动新创建的线程,使该被创建的线程状态变为可运行状态。当你调用方法的时候,只会是在原来的线程中调用,没有新的线程启动,方法才会启动新线程。如果我们调用了的方法,它的行为就会和普通的方法一样,直接运行方法。为了在新的线程中执行我们的代码,必须使用方法。

和都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。

  都可以用来让一组线程等待其它线程。与不同的是,不能重新使用。

Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性地行为。它在多线程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系确保了:

  • 线程内的代码能够按先后顺序执行,这被称为程序次序规则。

  • 对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则。

  • 前一个对的写操作在后一个的读操作之前,也叫变量规则。

  • 一个线程内的任何操作必需在这个线程的调用之后,也叫作线程启动规则。

  • 一个线程的所有操作都会在线程终止之前,线程终止规则。

  • 一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。

强烈建议大家阅读《Java并发编程实践》第十六章来加深对Java内存模型的理解。

是一个特殊的修饰符,只有成员变量才能使用它。在并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。变量可以保证下一个读取操作会在前一个写操作之后发生。线程都会直接从内存中读取该变量并且不缓存它。这就确保了线程读取到的变量是同内存中是一致的。

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的不是线程安全的。

在大多数实际的多线程应用中,两个或两个以上的线程需要共享对同一数据的存取。如果i线程存取相同的对象,并且每一个线程都调用了一个修改该对象状态的方法,将会发生什么呢?可以想象,线程彼此踩了对方的脚。根据线程访问数据的次序,可能会产生讹误的对象。这样的情况通常称为竞争条件。

提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像,  的控制方法,但是由于潜在的死锁威胁。因此在后续的JDK版本中他们被弃用了,之后的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当或者 方法执行完的时候线程会自动结束,如果要手动结束一个线程,可以用 布尔变量来退出方法的循环或者是取消任务来中断线程。

如果异常没有被捕获该线程将会停止执行。是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用来查询线程的并将线程和异常作为参数传递给的方法进行处理。

你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。这篇教程《Java线程间通信》(涉及到在两个线程间共享对象)用wait和notify方法实现了生产者消费者模型。

这又是一个刁钻的问题,因为多线程可以等待单监控锁, 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。

一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的方法就有意义了。如果方法定义在类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,和都是锁级别的操作,所以把他们定义在类中因为锁属于对象。

是Java里一种特殊的变量。每个线程都有一个就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获得了线程安全。

在Java并发程序中表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。一个对象可以对调用了和的对象进行包装,由于也是调用了接口所以它可以提交给Executor来执行。

和的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的,调用来中断一个线程就会设置中断标识为true。当中断线程调用静态方法来检查中断状态时,中断状态会被清零。而非静态方法用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出异常的方法都会将中断状态清零。无论如何,一个线程的中断状态有有可能被其它线程调用中断来改变。

当一个线程需要调用对象的方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的方法。同样的,当一个线程需要调用对象的方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。如果你不这么做,代码会抛出异常。

处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。因此,当一个等待线程醒来时,不能认为它原来的等待状态仍然是有效的,在方法调用之后和等待线程醒来之前这段时间它可能会改变。这就是在循环中使用方法效果更好的原因,你可以在Eclipse中创建模板调用和试一试。如果你想了解更多关于这个问题的内容,推荐你阅读《Effective Java》这本书中的线程和同步章节。

同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性。Java5介绍了并发集合像,不仅提供线程安全还用锁分离和内部分区等现代技术提高了可扩展性。

为什么把这个问题归类在多线程和并发面试题里?因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时 变量就可以发挥作用了,它要求线程从主存中读取变量的值。

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从开始,提供了框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。

在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 来实现生产者消费者模型。

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。

  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

这是上题的扩展,活锁和死锁类似,不同之处在于处于活锁的线程或进程的状态是不断改变的,活锁可以认为是一种特殊的饥饿。一个现实的活锁例子是两个人在狭小的走廊碰到,两个人都试着避让对方好让彼此通过,但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是,活锁和死锁的主要区别是前者进程的状态可以改变但是却不能继续执行。

在中有一个方法叫,它返回true如果当且仅当当前线程拥有某个具体对象的锁。

对于不同的操作系统,有多种方法来获得Java进程的线程堆栈。当你获取线程堆栈时,JVM会把所有线程的状态存到日志文件或者输出到控制台。在Windows你可以使用组合键来获取线程堆栈,下用命令。你也可以用这个工具来获取,它对线程id进行操作,你可以用这个工具找到id。

这个问题很简单,参数用来控制线程的堆栈大小。你可以查看配置列表来了解这个参数的更多信息。

在过去很长一段时间只能通过关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 通过接口提供了更复杂的控制来解决这些问题。 类实现了 Lock,它拥有与  相同的并发性和内存语义且它还具有可扩展性。

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。

yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃占用而不能保证使其它线程一定能占用,执行的线程有可能在进入到暂停状态后马上又被执行。点击这里查看更多方法的相关内容。

把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免争用。

Java中的Semaphore是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 ,然后再获取该许可。每个 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,比如数据库连接池。更多详细信息请点击这里。

这个问题问得很狡猾,许多程序员会认为该任务会阻塞直到线程池队列有空位。事实上如果一个任务不能被调度执行那么方法将会抛出一个异常。

两个方法都可以向线程池提交任务,方法的返回类型是,它定义在接口中, 而方法可以返回持有计算结果的Future对象,它定义在接口中,它扩展了接口,其它线程池类像和都有这些方法。更多详细信息请点击这里。

阻塞式方法是指程序会一直等待该方法完成期间不做其他事情,的法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。更多详细信息请点击这里。

每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的()。我们可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个,1代表最低优先级,10代表最高优先级。

线程调度器是一个操作系统服务,它负责为状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。时间分片是指将可用的CPU时间分配给可用的线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的)。

是存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。是多任务操作系统和多线程环境的基本特征。

对象可以在没有同步的情况下共享,降低了对该对象进行并发访问时的同步化开销。要创建不可变类,要实现下面几个步骤:通过构造方法初始化所有成员、对变量不要提供方法、将所有的成员声明为私有的,这样就不允许直接访问这些成员、在方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝。

一般而言,读写锁是用来提升并发程序性能的锁分离技术的成果。Java中的是Java 5 中新增的一个接口,一个维护一对关联的锁,一个用于只读操作一个用于写。在没有写线程的情况下一个读锁可能会同时被多个读线程持有。写锁是独占的,你可以使用中的来实现这个规则,它最多支持65535个写锁和65535个读锁。

忙循环就是程序员用循环让一个线程等待,不像传统方法, 或它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。

这是个有趣的问题。首先, 变量和  变量看起来很像,但功能却不一样。变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用volatile修饰变量那么  操作就不是原子性的。而类提供的方法可以让这种操作具有原子性如方法会原子性的进行增量操作把当前值加一,其它数据类型和引用变量也可以进行相似操作。

这个问题坑了很多程序员,若你能想到锁是否释放这条线索来回答还有点希望答对。无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我们更喜欢同步块,因为它不用花费精力去释放锁,该功能可以在里释放锁实现。

这个问题在面试中经常被问到,但是面试官对回答此问题的满意度仅为。一半的人写不出双检锁还有一半的人说不出它的隐患和是如何对它修正的。它其实是一个用来创建线程安全的单例的老方法,当单例实例第一次被创建时它试图用单个锁进行性能优化,但是由于太过于复杂在中它是失败的。

这是上面那个问题的后续,如果你不喜欢双检锁而面试官问了创建类的替代方法,你可以利用的类加载和静态变量初始化特征来创建实例,或者是利用枚举类型来创建。

以下三条最佳实践大多数Java程序员都应该遵循:

  • 给你的线程起个有意义的名字。

这样可以方便找bug或追踪。, 这种名字比  好多了,给线程起一个和它要完成的任务相关的名字,所有的主要框架甚至JDK都遵循这个最佳实践。

  • 避免锁定和缩小同步的范围

锁花费的代价高昂且上下文切换更耗费时间空间,试试最低限度的使用同步和锁,缩小临界区。因此相对于同步方法我更喜欢同步块,它给我拥有对锁的绝对控制权。

  • 多用同步类少用和 

首先,, ,  这些同步类简化了编码操作,而用wait和notify很难实现对复杂控制流的控制。其次,这些类是由最好的企业编写和维护在后续的JDK中它们还会不断优化和完善,使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。

  • 多用并发集合少用同步集合

这是另外一个容易遵循且受益巨大的最佳实践,并发集合比同步集合的可扩展性更好,所以在并发编程时使用并发集合效果更好。如果下一次你需要用到map,你应该首先想到用。

这个问题就像是如何强制进行Java垃圾回收,目前还没有觉得方法,虽然你可以使用来进行垃圾回收,但是不保证能成功。在Java里面没有办法强制启动一个线程,它是被线程调度器控制着且Java没有公布相关的。

框架是JDK7中出现的一款高效的工具,开发人员可以通过它充分利用现代服务器上的多处理器。它是专门为了那些可以递归划分成许多子模块设计的,目的是将所有可用的处理能力用来提升程序的性能。f

框架一个巨大的优势是它使用了工作窃取算法,可以完成更多任务的工作线程可以从其它线程中窃取任务来执行。

Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而方法仅仅释放资源或者让当前线程停止执行一段时间,但不会释放锁。需要注意的是,并不会让线程终止,一旦从休眠中唤醒线程,线程的状态将会被改变为,并且根据线程调度,它将得到执行。

是一个类,它的目的是提供关于线程组的信息。

比较薄弱,它并没有比Thread提供了更多的功能。它有两个主要的功能:一是获取线程组中处于活跃状态线程的列表;二是设置为线程设置未捕获异常处理器()。但在Java 1.5中Thread类也添加了方法,所以是已经过时的,不建议继续使用。

线程转储是一个活动线程的列表,它对于分析系统瓶颈和死锁非常有用。有很多方法可以获取线程转储——使用,命令,工具等等。我们更喜欢工具,因为它容易使用并且是JDK自带的。由于它是一个基于终端的工具,所以我们可以编写一些脚本去定时的产生线程转储以待分析。

是一个工具类,可以用于安排一个线程在未来的某个特定时间执行。类可以用安排一次性任务或者周期任务。

是一个实现了接口的抽象类,我们需要去继承这个类来创建我们自己的定时任务并使用Timer去安排它的执行。

原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。

并不是一个原子操作,所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,这就会引发错误。

 包中添加原子变量类之后,这种情况才发生了改变。所有原子变量类都公开比较并设置原语(与比较并交换类似),这些原语都是使用平台上可用的最快本机结构(比较并交换、加载链接/条件存储,最坏的情况下是旋转锁)来实现的。包中提供了原子变量的 9 种风格(;;;;原子整型;长型;引用;及原子标记引用和戳记引用类的数组形式,其原子地更新一对值)。

Lock接口比同步方法和同步块提供了更具扩展性的锁操作。他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象。

  • 可以使线程在等待锁的时候响应中断

  • 可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间

  • 可以在不同的范围,以不同的顺序获取和释放锁

框架同 接口在Java 5中被引入。框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。

无限制的创建线程会引起应用程序内存溢出。所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以回收再利用这些线程。利用框架可以非常方便的创建一个线程池。

为,,,和类提供了一些工具方法。

Executors可以用于方便的创建线程池。

的特性是:当队列是空的时,从队列中获取或删除元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。

阻塞队列不接受空值,当你尝试向队列中添加空值的时候,它会抛出。

阻塞队列的实现都是线程安全的,所有的查询方法都是原子的并且使用了内部锁或者其他形式的并发控制。

 接口是框架的一部分,它主要用于实现生产者-消费者问题。

在包中引入了 接口,它和接口很相似,但它可以返回一个对象或者抛出一个异常。

接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法去在线程池中执行Callable内的任务。由于Callable任务是并行的,我们必须等待它返回的结果。对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它我们可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。

包装器是一种非常便利的机制,可将转换成和它同时实现两者的接口。

类是Future 的一个实现,并实现了,所以可通过Excutor(线程池) 来执行。也可传递给Thread对象执行。如果在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过对象获得后台作业的计算结果或者执行状态。

Java集合类都是快速失败的,这就意味着当集合被改变且一个线程在使用迭代器遍历集合的时候,迭代器的next()方法将抛出异常。

并发容器:并发容器是针对多个线程并发访问设计的,在jdk5.0引入了concurrent包,其中提供了很多并发容器,如,等。

并发容器使用了与同步容器完全不同的加锁策略来提供更高的并发性和伸缩性,例如:在中采用了一种粒度更细的加锁机制,可以称为分段锁,在这种锁机制下,允许任意数量的读线程并发地访问map,并且执行读操作的线程和写操作的线程也可以并发的访问map,同时允许一定数量的写操作线程并发地修改map,所以它可以在并发环境下实现更高的吞吐量。

当我们在Java程序中创建一个线程,它就被称为用户线程。一个守护线程是在后台执行并且不会阻止终止的线程。当没有用户线程在运行的时候,JVM关闭程序并且退出。一个守护线程创建的子线程依然是守护线程。

当我们在Java程序中新建一个线程时,它的状态是New。当我们调用线程的start()方法时,状态被改变为Runnable。线程调度器会为线程池中的线程分配CPU时间并且讲它们的状态改变为。其他的线程状态还有,和。

当线程间是可以共享资源时,线程间通信是协调它们的重要的手段。Object类中方法可以用于线程间通信关于资源的锁的状态。

Thread类的sleep()和yield()方法将在当前正在执行的线程上运行。所以在其他处于等待状态的线程上调用这些方法是没有意义的。这就是为什么这些方法是静态的。它们可以在当前正在执行的线程中工作,并避免程序员错误的认为可以在其他非运行线程调用这些方法。

在Java中可以有很多方法来保证线程安全——同步,使用原子类(),实现并发锁,使用volatile关键字,使用不变类和线程安全类。

同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。

使用Thread类的方法可以将线程设置为守护线程,需要注意的是,需要在调用方法前调用这个方法,否则会抛出异常。

(1) 抢占式调度策略

Java运行时系统的线程调度算法是抢占式的 ()。Java运行时系统支持一种简单的固定优先级的调度算法。如果一个优先级比其他任何处于可运行状态的线程都高的线程进入就绪状态,那么运行时系统就会选择该线程运行。新的优先级较高的线程抢占()了其他线程。但是Java运行时系统并不抢占同优先级的线程。换句话说,Java运行时系统不是分时的()。然而,基于类的实现系统可能是支持分时的,因此编写代码时不要依赖分时。当系统中的处于就绪状态的线程都具有相同优先级时,线程调度程序采用一种简单的、非抢占式的轮转的调度顺序。

(2) 时间片轮转调度策略

有些系统的线程调度采用时间片轮转()调度策略。这种调度策略是从所有处于就绪状态的线程中选择优先级最高的线程分配一定的CPU时间运行。该时间过后再选择其他线程运行。只有当线程运行结束、放弃()CPU或由于某种原因进入阻塞状态,低优先级的线程才有机会执行。如果有两个优先级相同的线程都在等待CPU,则调度程序以轮转的方式选择运行的线程。

是中的新接口,它允许我们在每一个对象上添加一个异常处理器。

觉得up主总结的不错的:点点赞+评论+关注阿婆主 ,最后评论“学习”领取最全套Java面试题一份哦!

}
A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解并发理论基础和线程基础,并发关键字等,这些是你理解Java并发框架的基础。@pdai
    • 多线程的出现是要解决什么问题的?
    • 线程不安全是指什么?举例说明
    • 并发出现线程不安全的本质什么?可见性,原子性和有序性。
    • 线程安全是不是非真即假?不是
    • 线程安全有哪些实现思路?
    • 如何理解并发和并行的区别?
    • 线程有哪几种状态?分别说明从一种状态到另一种状态转变有哪些方式?
    • 通常线程有哪几种使用方式?
    • 线程的中断方式有哪些?
    • 线程的互斥同步方式有哪些?如何比较和选择?
    • 线程之间有哪些协作方式?
    • Synchronized可以作用在哪里?分别通过对象锁和类锁进行举例。
    • Synchronized本质上是通过什么保证线程安全的?分三个方面回答:加锁和释放锁的原理,可重入原理,保证可见性原理。
    • Synchronized修饰的方法在抛出异常时,会释放锁吗?
    • 多个线程等待同一个snchronized锁的时候,JVM如何选择下一个获取锁的线程?
    • Synchronized使得同时只有一个线程可以执行,性能比较差,有什么提升的方法?
    • 我想更加灵活地控制锁的释放和获取(现在释放锁和获取锁的时机都被规定死了),怎么办?
    • 什么是锁的升级和降级?什么是JVM里的偏斜锁、轻量级锁、重量级锁?
    • volatile关键字的作用是什么?
    • 之前32位机器上共享的long和double变量的为什么要用volatile?现在64位机器上是否也要设置呢?
    • i++为什么不能保证原子性?
    • volatile是如何实现可见性的? 内存屏障。
    • 所有的final修饰的字段都是编译期常量吗?
    • 如何理解private所修饰的方法是隐式的final?
    • 说说final类型的类如何拓展?比如String是final类型,我们想写个MyString复用所有String中方法,同时增加一个新的toMyString()的方法,应该如何做?
    • final方法可以被重载吗?可以
    • 父类的final方法能不能够被子类重写?不可以
    • 说说final域重排序规则?
    • 说说final的原理?
    • 使用 final 的限制条件和局限性?
    • 看本文最后的一个思考题
B. Java进阶 - Java 并发之J.U.C框架:然后需要对J.U.C框架五大类详细解读,包括:Lock框架,并发集合, 原子类, 线程池和工具类。@pdai
    • JUC框架包含几个部分?
    • 每个部分有哪些核心的类?
    • 线程安全的实现方法有哪些?
    • 针对这这些问题,Java提供了哪几个解决的?
    • 请阐述你对Unsafe类的理解?
    • 说说你对Java原子类的理解?包含13个,4组分类,说说作用和使用场景。
    • 什么是AQS?为什么它是核心?
    • AQS的核心思想是什么?它是怎么实现的?底层数据结构等
    • AQS有哪些核心的方法?
    • AQS定义什么样的资源获取方式?AQS定义了两种资源获取方式:独占(只有一个线程能访问执行,又根据是否按队列的顺序分为公平锁非公平锁,如ReentrantLock)
    • AQS底层使用了什么样的设计模式?模板
    • 什么是可重入,什么是可重入锁?它用来解决什么问题?
    • ReentrantLock的核心是AQS,那么它怎么来实现的,继承吗?说说其类内部结构关系。
    • ReentrantLock默认实现的是公平还是非公平锁?
    • 使用ReentrantLock实现公平和非公平锁的示例?
    • 读锁和写锁的最大数量是多少?
    • 缓存计数器HoldCounter是用来做什么的?
    • 写锁的获取与释放是怎么实现的?
    • 读锁的获取与释放是怎么实现的?
B.3 Java进阶 - Java 并发之J.U.C框架【3/5】:集合:再理解JUC中重要的支持并发的集合。
    • 请先说说非并发集合中Fail-fast机制?
    • 再为什么说ArrayList查询快而增删慢?
B.4 Java进阶 - Java 并发之J.U.C框架【4/5】:线程池:再者分析JUC中非常常用的线程池等。
    • FutureTask用来解决什么问题的?为什么会出现?
    • FutureTask的线程安全是由什么保证的?
    • FutureTask通常会怎么用?举例说明。
    • Java是实现和管理线程池有哪些方式? 请简单举例如何使用。
    • 为什么很多公司不允许使用Executors去创建线程池?那么推荐怎么使用呢?
    • 当队列满了并且worker的数量达到maxSize的时候,会怎么样?
    • 线程池中任务是如何提交的?
    • 线程池中任务是如何关闭的?
    • 在配置线程池的时候需要考虑哪些配置因素?
    • 如何监控线程池的状态?
    • Fork/Join主要用来解决什么样的问题?
    • Fork/Join框架是在哪个JDK版本中引入的?
    • Fork/Join框架主要包含哪三个模块?模块之间的关系是怎么样的?
    • 整个Fork/Join 框架的执行流程/运行机制是怎么样的?
    • Fork/Join在使用时有哪些注意事项?结合JDK中的斐波那契数列实例具体说明。
    • 写道题:实现一个容器,提供两个方法,add,size 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束? 使用CountDownLatch 代替wait notify 好处。
    • Semaphore常用方法有哪些?如何实现线程同步和互斥的?
    • 单独使用Semaphore是不会使用到AQS的条件队列?
    • Semaphore初始化有10个令牌,11个线程同时各调用1次acquire方法,会发生什么?
    • Semaphore初始化有10个令牌,一个线程重复调用11次acquire方法,会发生什么?
    • Semaphore初始化有1个令牌,1个线程调用一次acquire方法,然后调用两次release方法,之后另外一个线程调用acquire(2)方法,此线程能够获取到足够的令牌并继续运行吗?
    • Semaphore初始化有2个令牌,一个线程调用1次release方法,然后一次性获取3个令牌,会获取到吗?
    • Phaser主要用来解决什么问题?
    • Phaser运行机制是什么样的?
    • 给一个Phaser使用的示例?
    • Exchanger在不同的JDK版本中实现有什么差别?
    • Exchanger已经有了slot单节点,为什么会加入arena node数组?什么时候会用到数组?
    • arena可以确保不同的slot在arena中是不会相冲突的,那么是怎么保证的呢?
    • 什么是伪共享,Exchanger中如何体现的?
    • 什么是ThreadLocal?用来解决什么问题的?
    • 为什么ThreadLocal会造成内存泄露?如何解决
    • 还有哪些使用ThreadLocal的应用场景?
}

我要回帖

更多关于 编程对cpu要求怎么样 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信