java 多线程T(重写) --- 5---2021-10-09

2021-10-09  本文已影响0人  鄙人_阿K

《面试题对标大纲》

题目列表集

1、CAS 的会产生什么问题?
2、什么是原子类
3、原子类的常用类
4、说一下 Atomic的原理?
5、死锁与活锁的区别,死锁与饥饿的区别?
6、什么是线程池?
7、线程池作用?
8、线程池有什么优点?
9、什么是ThreadPoolExecutor?
10、什么是Executors?
11、线程池四种创建方式?
12、在 Java 中 Executor 和 Executors 的区别?
13、四种构建线程池的区别及特点?
14、线程池都有哪些状态?
15、线程池中 submit() 和 execute() 方法有什么区别?
16、什么是线程组,为什么在 Java 中不推荐使用?
17、ThreadPoolExecutor饱和策略有哪些?
18、如何自定义线程线程池?
19、线程池的执行原理?
20、如何合理分配线程池大小?

1、CAS 的会产生什么问题?

1、ABA 问题:
比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且 two 进
行了一些操作变成了 B,然后 two 又将 V 位置的数据变成 A,这时候线程 one 进行 CAS 操作发现内存
中仍然是 A,然后 one 操作成功。尽管线程 one 的 CAS 操作成功,但可能存在潜藏的问题。从
Java1.5 开始 JDK 的 atomic包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。

2、循环时间长开销大:
对于资源竞争严重(线程冲突严重)的情况,CAS 自旋的概率会比较大,从而浪费更多的 CPU 资源,
效率低于 synchronized。

3、只能保证一个共享变量的原子操作:
当对一个共享变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操作,但是对多个共享变量
操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁。

2、什么是原子类

★ 简单来说就是:原子类来实现CAS无锁模式的算法

3、原子类的常用类

AtomicBoolean
AtomicInteger
AtomicLong
AtomicReference

4、说一下 Atomic的原理?

Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引
用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线
程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。

5、死锁与活锁的区别,死锁与饥饿的区别?

6、什么是线程池?

Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用
线程池。在开发过程中,合理地使用线程池能够带来许多好处。

(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
(3)提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降
(4)低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用

7、线程池作用?

8、线程池有什么优点?

9、什么是ThreadPoolExecutor?

ThreadPoolExecutor就是线程池

ThreadPoolExecutor其实也是JAVA的一个类,我们一般通过Executors工厂类的方法,通过传入
不同的参数,就可以构造出适用于不同应用场景下的ThreadPoolExecutor(线程池)


image.png

对此构造解读:
corePoolSize 核心线程数量
maximumPoolSize 最大线程数量
keepAliveTime 线程保持时间,N个时间单位
unit 时间单位(比如秒,分)
workQueue 阻塞队列
threadFactory 线程工厂
handler 线程池拒绝策略

10、什么是Executors?

Executors框架实现的就是线程池的功能。

Executors工厂类中提供的newCachedThreadPool、newFixedThreadPool 、
newScheduledThreadPool 、newSingleThreadExecutor 等方法其实也只是
ThreadPoolExecutor的构造函数参数不同而已。通过传入不同的参数,就可以构造出适用于不同
应用场景下的线程池

Executor工厂类如何创建线程池图:


image.png

11、线程池四种创建方式?

Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
  1. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回
    收空闲线程,若无可回收,则新建线程。

  2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列
    中等待。

  3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

  4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任
    务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

12、在 Java 中 Executor 和 Executors 的区别?

13、四种构建线程池的区别及特点?

1、newCachedThreadPool
package com.kk;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestNewCachedThreadPool {
    public static void main(String[] args) {
        // 创建无限大小线程池,由jvm自动回收 
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool ( );
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newCachedThreadPool.execute (new Runnable ( ) {
                public void run() {
                    try {
                        Thread.sleep (100);
                    } catch (Exception e) {
                    }
                    System.out.println (Thread.currentThread ( ).getName ( ) + ",i==" + temp);
                }
            });
        }
    }
}
2、newFixedThreadPool

Runtime.getRuntime().availableProcessors()方法是查看电脑CPU核心数量)

package com.kk;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestNewFixedThreadPool {
    public static void main(String[] args) {
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool (3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newFixedThreadPool.execute (new Runnable ( ) {
                public void run() {

                    System.out.println (Thread.currentThread ( ).getName ( ) + ",i==" + temp);
                }
            });
        }
    }
}
3、newScheduledThreadPool
package com.lijie;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TestNewScheduledThreadPool {
    public static void main(String[] args) {
        //定义线程池大小为3 
        ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool (3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newScheduledThreadPool.schedule (new Runnable ( ) {
                public void run() {
                    System.out.println ("i:" + temp);
                }
            }, 3, TimeUnit.SECONDS);//这里表示延迟3秒执行。
        }
    }
}
CSDN博客:Timer定时器用法详解,java原生定时器
4、newSingleThreadExecutor
package com.kk;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestNewSingleThreadExecutor {
    public static void main(String[] args) {
        ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor ( );
        for (int i = 0; i < 10; i++) {
            final int index = i;
            newSingleThreadExecutor.execute (new Runnable ( ) {
                public void run() {
                    System.out.println (Thread.currentThread ( ).getName ( ) + " index:" + index);
                    try {
                        Thread.sleep (200);
                    } catch (Exception e) {
                    }
                }
            });
        }
    }
}

14、线程池都有哪些状态?

15、线程池中 submit() 和 execute() 方法有什么区别?

16、什么是线程组,为什么在 Java 中不推荐使用?

17、ThreadPoolExecutor饱和策略有哪些?

如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,ThreadPoolTaskExecutor 定 义一些策略:

18、如何自定义线程线程池?(其实上面的 #9也有重复部分,帮助记忆在放一遍)

构造参数参数介绍::

corePoolSize 核心线程数量
maximumPoolSize 最大线程数量
keepAliveTime 线程保持时间,N个时间单位
unit 时间单位(比如秒,分)
workQueue 阻塞队列
threadFactory 线程工厂
handler 线程池拒绝策略

package com.kk;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test001 {
    public static void main(String[] args) { //创建线程池

        ThreadPoolExecutor executor = new ThreadPoolExecutor (1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<> (3));
        for (int i = 1; i <= 6; i++) {
            TaskThred t1 = new TaskThred ("任务" + i);
            executor.execute (t1);
            //是执行线程方法 
            executor.execute (t1);
        }
        executor.shutdown ( );
        //不再接受新的任务,并且等待之前提交的任务都执行完再关 闭,阻塞队列中的任务不会再执行。 
        executor.shutdown ( );
    }
}

class TaskThred implements Runnable {
    private String taskName;

    public TaskThred(String taskName) {
        this.taskName = taskName;
    }

    public void run() {
        System.out.println (Thread.currentThread ( ).getName ( ) + taskName);
    }
}

19、线程池的执行原理?

image.png

20、如何合理分配线程池大小?

一、什么是CPU密集
二、什么是IO密集
三、分配CPU和IO密集
  1. CPU密集型时,任务可以少配置线程数,大概和机器的cpu核数相当,这样可以使得每个线程都在
    执行任务

  2. IO密集型时,大部分线程都阻塞,故需要多配置线程数,2*cpu核数

四、从以下几个角度分析任务的特性:

任务的性质:CPU密集型任务、IO密集型任务、混合型任务。
任务的优先级:高、中、低。
任务的执行时间:长、中、短。
任务的依赖性:是否依赖其他系统资源,如数据库连接等。

五、结论

线程等待时间比CPU执行时间比例越高,需要越多线程。
线程CPU执行时间比等待时间比例越高,需要越少线程。

上一篇 下一篇

猜你喜欢

热点阅读