Java面试题-多线程

多线程

进程、线程

        1.进程包括线程。

        2.如果一个进程只有一个线程,这种程序被称为单线程。

        3.如果一个进程中有多条执行路径被称为多线程程序。

        4.一个进程中可以有多个线程,每个进程有自己独立的内存,每个线程共享一个进程中的内存,每个线程又有自己独立的内存。

多线程的特性:随机性

线程生命周期,总共有五种状态:

        1) 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

        2) 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

        3) 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

        4) 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态; 根据阻塞产生的原因不同,阻塞状态又可以分为三种:

                a) 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

                b) 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

                c) 其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

        5) 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

实现多线程

Java面试题-多线程_第1张图片

JVM启动是单线程还是多线程?

        多线程,最少要启动main线程和GC线程。

线程锁

悲观锁和乐观锁

悲观锁:还是像它的名字一样,对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。

乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。

两种常见的锁

Synchronized 互斥锁(悲观锁,有罪假设)

采用synchronized修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。

ReentrantReadWriteLock 读写锁(乐观锁,无罪假设)

ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,实际上独占锁是一种相对比较保守的锁策略,在这种情况下任何“读/读”、“读/写”、“写/写”操作都不能同时发生,这在一定程度上降低了吞吐量。然而读操作之间不存在数据竞争问题,如果”读/读”操作能够以共享锁的方式进行,那会进一步提升性能。因此引入了ReentrantReadWriteLock,顾名思义,ReentrantReadWriteLock是Reentrant(可重入)Read(读)Write(写)Lock(锁),我们下面称它为读写锁。

读写锁内部又分为读锁和写锁,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。读锁和写锁分离从而提升程序性能,读写锁主要应用于读多写少的场景。

需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁会自动释放,而是用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内! 

线程池有几种?

Java通过Executors(JUC)提供四种线程池,分别为:

1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活 回收空闲线程,若无可回收,则新建线程。

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

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

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

线程池参数有哪些?

        corePoolSize 核心线程大小。

        maximumPoolSize 线程池最大线程数量。

        keepAliveTime 空闲线程存活时间。

        unit 空间线程存活时间单位。

        workQueue 工作队列。

        threadFactory 线程工厂。

        handler 拒绝策略。

你可能感兴趣的:(笔记,java,jvm,面试)