Java面试题(每天10题)-------连载(25)

目录

多线程篇

1、什么是线程

2、什么是线程安全和线程不安全? 

3、什么是自旋锁?

4、什么是CAS?

5、什么是乐观锁和悲观锁?

6、什么是AQS?

7、什么是原子操作?在Java Concurrency API中有那些原子类(atomic classes)?

8、什么是Executors框架?

9、什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?

10、什么是Callable和Future?


多线程篇

1、什么是线程

线程是操作系统能够进⾏运算调度的最⼩单位,它被包含在进程之中,是进程中的实际运作单位,可以使⽤多线程对进⾏运算提速。
比如:如果一个线程完成一个任务要100ms,那么十个线程完成该任务只需要10ms。 

2、什么是线程安全和线程不安全? 

1 、线程安全
线程安全 : 就是多线程访问时,采⽤了加锁机制,当⼀个线程访问该类的某个数据时,进⾏保护,其他线程不能进⾏访问,直到该线程读取完,其他线程才可使⽤。不会出现数据不⼀致或者数据污染。
Vector 是⽤同步⽅法来实现线程安全的, ⽽和它相似的 ArrayList 不是线程安全的。
2 、线程不安全
线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,⽽⽆写操作,⼀般来说,这个全局变量是线程安全的;若有多个线程同时执⾏写操作,⼀般都需要考虑线程同步,否则的话就可能影响线程安全。 

3、什么是自旋锁?

⾃旋锁是 SMP 架构中的⼀种 low-level 的同步机制。
1 、当线程 A 想要获取⼀把⾃旋锁⽽该锁⼜被其它线程锁持有时,线程 A 会在⼀个循环中⾃旋以检测锁是不是已经可⽤了。
2 、⾃选锁需要注意:
  • 由于⾃旋时不释放CPU,因⽽持有⾃旋锁的线程应该尽快释放⾃旋锁,否则等待该⾃旋锁的线程会⼀直在那⾥⾃旋,这就会浪费CPU时间。
  • 持有⾃旋锁的线程在sleep之前应该释放⾃旋锁以便其它线程可以获得⾃旋锁。
3 、⽬前的 JVM 实现⾃旋会消耗 CPU ,如果⻓时间不调⽤ doNotify ⽅法, doWait ⽅法会⼀直⾃旋, CPU 会消耗太⼤。
4 ⾃旋锁⽐较适⽤于锁使⽤者保持锁时间⽐较短的情况,这种情况⾃旋锁的效率⽐较⾼。
5 ⾃旋锁是⼀种对多处理器相当有效的机制,⽽在单处理器 ⾮抢占式 的系统中基本上没有作⽤

4、什么是CAS?

1、CAS(compare and swap)的缩写,中⽂翻译成⽐较并交换。

2 CAS 不通过 JVM ,直接利⽤ java 本地⽅ JNI Java Native Interface JAVA 本地调⽤),直接调⽤ CPU cmpxchg (是汇编指令)指令。
3 、利⽤ CPU CAS 指令,同时借助 JNI 来完成 Java 的⾮阻塞算法,实现原⼦操作。其它原⼦操作都是利⽤类似的特性完成的。
4 、整个 java.util.concurrent 都是建⽴在 CAS 之上的,因此对于 synchronized 阻塞算法, J.U.C 在性能上有了很⼤的提升。
5 CAS是项乐观锁技术 ,当多个线程尝试使⽤ CAS 同时更新同⼀个变量时,只有其中⼀个线程能更新变量的值,⽽其它线程都失败,失败的线程并不会被挂起,⽽是被告知这次竞争中失败,并可以再次尝试。

5、什么是乐观锁和悲观锁?

1 、悲观锁
Java JDK1.5 之前都是靠 synchronized 关键字保证同步的,这种通过使⽤⼀致的锁定协议来协调对共享状态的访问,可以确保⽆论哪个线程持有共享变量的锁,都采⽤独占的⽅式来访问这些变量。独占锁其实就是⼀种悲观锁,所以可以说synchronized 是悲观锁。
2 、乐观锁
乐观锁( Optimistic Locking )其实是⼀种思想。相对悲观锁⽽⾔,乐观锁假设认为数据⼀般情况下不会造成冲突,所以在数据进⾏提交更新的时候,才会正式对数据的冲突与否进⾏检测,如果发现冲突了,则让返回⽤户错误的信息,让⽤户决定如何去做。

6、什么是AQS?

1 AbstractQueuedSynchronizer 简称 AQS ,是⼀个⽤于构建锁和同步容器的框架。事实上 concurrent 包内许多类都是基于AQS 构建,例如 ReentrantLock Semaphore CountDownLatch ReentrantReadWriteLock FutureTask 等。 AQS 解决了在实现同步容器时设计的⼤量细节问题。

2 AQS 使⽤⼀个 FIFO 的队列表示排队等待锁的线程,队列头节点称作“哨兵节点”或者“哑节点”,它不与任何线程关联。其他的节点与等待线程关联,每个节点维护⼀个等待状态waitStatus

7、什么是原子操作?在Java Concurrency API中有那些原子类(atomic classes)?

1 、原⼦操作是指⼀个不受其他操作影响的操作任务单元。原⼦操作是在多线程环境下避免数据不⼀致必须的⼿段。
2 int++ 并不是⼀个原⼦操作,所以当⼀个线程读取它的值并加 1 时,另外⼀个线程有可能会读到之前的值,这就会引发错误。
3 、为了解决这个问题,必须保证增加操作是原⼦的,在 JDK1.5 之前我们可以使⽤同步技术来做到这⼀点。到JDK1.5 java.util.concurrent.atomic 包提供了 int long 类型的装类,它们可以⾃动的保证对于他们的操作是原⼦的并且不需要使⽤同步。

8、什么是Executors框架?

Java通过Executors提供四种线程池,分别是:

1 newCachedThreadPool 创建⼀个 可缓存线程池 ,如果线程池⻓度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。
2 newFixedThreadPool 创建⼀个 定⻓线程池 ,可控制线程最⼤并发数,超出的线程会在队列中等待。
3 newScheduledThreadPool 创建⼀个 定⻓线程池 ,⽀持定时及周期性任务执⾏。
4 newSingleThreadExecutor 创建⼀个 单线程化的线程池 ,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。

9、什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?

1 JDK7 提供了 7 个阻塞队列。(也属于并发容器)
i. ArrayBlockingQueue :⼀个由数组结构组成的有界阻塞队列。
ii. LinkedBlockingQueue :⼀个由链表结构组成的有界阻塞队列。
iii. PriorityBlockingQueue :⼀个⽀持优先级排序的⽆界阻塞队列。
iv. DelayQueue :⼀个使⽤优先级队列实现的⽆界阻塞队列。
v. SynchronousQueue :⼀个不存储元素的阻塞队列。
vi. LinkedTransferQueue :⼀个由链表结构组成的⽆界阻塞队列。
vii. LinkedBlockingDeque :⼀个由链表结构组成的双向阻塞队列。
2 、概念:阻塞队列是⼀个在队列基础上⼜⽀持了两个附加操作的队列。
3 2 个附加操作:
⽀持阻塞的插⼊⽅法:队列满时,队列会阻塞插⼊元素的线程,直到队列不满。
⽀持阻塞的移除⽅法:队列空时,获取元素的线程会等待队列变为⾮空。

10、什么是Callable和Future?

1 Callable Future 是⽐较有趣的⼀对组合。当我们需要获取线程的执⾏结果时,就需要⽤到它们。 Callable ⽤于产⽣结果,Future ⽤于获取结果。
2 Callable 接⼝使⽤泛型去定义它的返回类型。 Executors 类提供了⼀些有⽤的⽅法去在线程池中执⾏ Callable 内的任务。由于Callable 任务是并⾏的,必须等待它返回的结果。 java.util.concurrent.Future 对象解决了这个问题。
3 、在线程池提交 Callable 任务后返回了⼀个 Future 对象,使⽤它可以知道 Callable 任务的状态和得到 Callable 返回的执⾏结果。Future 提供了 get ()⽅法,等待 Callable 结束并获取它的执⾏结果。

你可能感兴趣的:(java,开发语言)