线程
- 线程和进程的区别
- 线程
- 进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己不拥有自己的系统资源,只拥有一点运行中不必要不可少的资源(如程序计数器,一组寄存器和栈),但是他可与属于一个进程和其他的线程的共享进程所拥有的全部资源.
- 线程的生命周期
- 进程
- 具有一档独立的功能的程序关于某个数据集合上的一次运行活动,,进程是系统进行资源上分配和调度的一个独立的单位.
- 区别
- 一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以多个线程来增加程序的执行速度.
- 线程
- 守护线程是什么
- 守护线程是运行在后台的一种特殊的进程,他独立与控制终端并且周期性的执行某种任务或等待处理某些发生的事件,在Java中垃圾回收线程就是特殊的守护线程.
- 多线程有几种实现方式
- 有4种,分别是
- 继承Thread类
- 实现Runnable类
- 实现Callable接口通过FutureTask包装来创建Thread线程
- 通过线程池来创建线程,使用线程池接口ExecutorService结合Callable,Future实现有返回结果的多线程.
- 前面两种[无返回值]原因:通过重写run方法,run方法的返回值是void,所以没有办法返回结果.
- 后面两种[有返回值]原因:通过Callable接口,就是实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中.
- 有4种,分别是
- Runnable和Callable的区别
- Runnable没有返回值,Callable可以拿到返回值,Callable可以看作是Runnable的补充.
- 线程有哪些状态
- 图解(7种状态)
- 初始(NEW):新创建一个线程对象,但是没有调用start()方法.
- 就绪(Runable):Java线程中将就绪(reaby)和运行中(running)两种状态笼称为运行,线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法,该转让的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready),就绪状态的线程在获得CPU时间片后变为运行状态(running).
- 阻塞(Blocked):表示线程阻塞于锁.
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定的动作(通知或中断).
- 超时等待(TIMED_WAITING):该状态不同于WAITING,他可以在指定的时间后自行返回.
- 终止(TERMINATED):表示该线程已经执行完毕.
- 图解(7种状态)
- notify()和notifyAll()有什么区别
- notifyAll():会唤醒所有的线程,nofity():之后唤醒一个线程,notifyAll()调用后,会将全部的线程由等待池移到锁池,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后在参与竞争,而motify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制.
- 线程的run()和start()有什么区别
- start()方法用于启动线程,run()方法用于执行线程的运行时代码,run()可以重复调用,而start()只能调用一次.
- 创建线程池有几种方式(七种方式)
- newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
- newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列;
- newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;
- newSingleThreadScheduledExecutor():创建单线程池,返回 ScheduledExecutorService,可以进行定时或周期性的工作调度;
- newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
- newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
- ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor的封装。
- 线程池中submit()和execute()方法有什么区别
- execute():只能执行Runnable类型的任务
- submit():可以执行Runnable和Callable类型的任务
- Callable类型的任务可以获取执行的返回值,而Runnable执行无返回值.
- 在Java程序中怎么保证多线程的运行安全
- 方法一:使用安全类,比如Java.util.concurrent下的类
- 方法二:使用自动锁synchronized
- 方法三:使用手动锁Lock
- 手动锁Java实例代码如下
- 多线程中synchronized锁升级的原理是什么?
- synchronized锁升级的原理,在锁对象的对象头里面有一个threadid字段,在第一次访问的时候threadid为空,JVM让其待有偏向锁,并将threadid设置为其线程id,再次进入的是时候会先判断threadid是否与其线程id一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数后,如果没有正常获取到使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了synchronized的锁的升级,锁的升级的目的,锁升级是为了减轻了锁带来的性能消耗,在Java6之后优化synchronized的实现方式,使用了偏向锁升级为轻量级锁在升级到重量级锁的方式,从而减轻了锁带来的性能的消耗
- 什么是死锁
- 当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有的独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们叫做死锁.
- 怎么防止死锁
- 尽量使用tryLock(long timeout,TimeUnit unit)的方法(ReentrantLock ReentrantReadWriteLock),设置超时时间,超时可以防止退出防止死锁,尽量使用Java.util.concurrent并发类代替自己的手写锁,尽量降低的使用粒度,尽量不要几个功能同用一把锁,尽量减少同步代码的书写.
- 说一下 synchronized 底层实现原理?
- synchronized 是由一对 monitorenter/monitorexit 指令实现的,monitor 对象是同步的基本实现单元。在 Java 6 之前,monitor 的实现完全是依靠操作系统内部的互斥锁,因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作,性能也很低。但在 Java 6 的时候,Java 虚拟机 对此进行了大刀阔斧地改进,提供了三种不同的 monitor 实现,也就是常说的三种不同的锁:偏向锁(Biased Locking)、轻量级锁和重量级锁,大大改进了其性能。
- synchronized 和 volatile 的区别是什么?
- volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
- synchronized 和 Lock 有什么区别?
- synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁。synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
- 并发,并行有什么区别
- 并行
- 多个处理器或多核处理器同时处理多个任务
- 多个处理器或多核处理器同时处理多个任务
- 并发
- 多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看哪些任务是同时执行.
- 多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看哪些任务是同时执行.
- 并行
- 乐观锁,悲观锁,共享变量,死锁,线程池,分析业务场景与原理
- Volatile
- 什么叫线程安全
- 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束后才能对这个线程安全的方法进行访问,
- 什么叫做线程安全
- 如果你的代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也是预期的是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的,或者说,一个类或者程序提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不要考虑同步的问题,线程安全问题是由全局变量以及静态变量引起的,若每个线程中对全局变量,静态变量只有操作,而无写操作,一般来说,这个全局变量是线程安全的,若有多个线程同步执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全.
- 实现线程安全的方式有哪几种,常用的是哪一种,优缺点是什么
- 线程阻塞
- 线程异步
- 锁