精华内容
下载资源
问答
  • java锁机制面试题

    2020-04-18 16:10:52
    synchronized 和 lock 机制区别 synchronized 原始采用的是 CPU 悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。 Lock 用的是乐观锁方式。所谓乐观锁就是,每次不加锁...

    1、ABA问题

    CAS 会导致“ABA问题”。

    CAS 算法实现一个重要前提需要取出内存中某时刻的数据,而在下时刻比较并替换,那么在这个时间差类会导致数据的变化。

    比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且 two 进行了一些操作变成了 B,然后 two 又将 V 位置的数据变成 A,这时候线程 one 进行 CAS 操作发现内存中仍然是 A,然后 one 操作成功。尽管线程 one 的 CAS 操作成功,但是不代表这个过程就是没有问题的。

    部分乐观锁的实现是通过版本号(version)的方式来解决 ABA 问题,乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行 +1 操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现 ABA 问题,因为版本号只会增加不会减少。

    2、CAS乐观锁

    CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

    CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”这其实和乐观锁的冲突检查 + 数据更新的原理是一样的。

    3、synchronize实现原理

    1同步代码块是使用 monitorenter 和 monitorexit 指令实现的,同步方法(在这看不出来需要看 JVM 底层实现)依靠的是方法修饰符上的 ACC_SYNCHRONIZED 实现。

    4、synchronize与lock的区别

    synchronized 和 lock 的用法区别

     

    osynchronized(隐式锁):在需要同步的对象中加入此控制,synchronized 可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。

    olock(显示锁):需要显示指定起始位置和终止位置。一般使用 ReentrantLock 类做为锁,多个线程中必须要使用一个 ReentrantLock 类做为对象才能保证锁的生效。且在加锁和解锁处需要通过 lock() 和 unlock() 显示指出。所以一般会在 finally块中写 unlock() 以防死锁。

     

    synchronized 和 lock 性能区别 synchronized 是托管给 JVM 执行的,而 lock是 Java 写的控制锁的代码。在 JDK 1.5 中,synchronize 是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用 Java 提供的 Lock 对象,性能更高一些。但是到了 JDK 1.6,发生了变化。synchronize 在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在 JDK 1.6 上 synchronize 的性能并不比 Lock 差。

    synchronized 和 lock 机制区别

    synchronized 原始采用的是 CPU 悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。

    Lock 用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是 CAS 操作(Compare and Swap)。

    5、volatile实现原理

    在 JVM 底层 volatile 是采用“内存屏障”来实现的

    缓存一致性协议(MESI协议)它确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 CPU 在写数据时,如果发现操作的变量是共享变量,则会通知其他 CPU 告知该变量的缓存行是无效的,因此其他 CPU 在读取该变量时,发现其无效会重新从主存中加载数据

    6、乐观锁的业务场景及实现方式

    乐观锁(Optimistic Lock):

    每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。

    比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。

    7、说说线程安全的问题

    线程安全是多线程领域的问题,线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出现问题。

    在 Java 多线程编程当中,提供了多种实现 Java 线程安全的方式:

    最简单的方式,使用 Synchronization 关键字

    使用 java.util.concurrent.atomic 包中的原子类,例如 AtomicInteger

    使用 java.util.concurrent.locks 包中的锁

    使用线程安全的集合 ConcurrentHashMap

    使用 volatile关键字,保证变量可见性(直接从内存读,而不是从线程 cache 读)

    展开全文
  • 锁的原因都是由并发问题发生的,在此我只是写一些面试中可能会问到的问题以及问题的答案,并不是给大家深入的讲解锁机制 一般面试官问都是从一个点引入一个点的问问题,所以我就先从线程问题引入到锁问题 正文 1.说说...

    前言

    锁的原因都是由并发问题发生的,在此我只是写一些面试中可能会问到的问题以及问题的答案,并不是给大家深入的讲解锁机制

    一般面试官问都是从一个点引入一个点的问问题,所以我就先从线程问题引入到锁问题

    正文

    1.说说线程安全问题

    线程安全是多线程领域的问题,线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出现问题

    在 Java 多线程编程当中,提供了多种实现 Java 线程安全的方式:

    • 最简单的方式,使用 Synchronization 关键字
    • 使用 java.util.concurrent.atomic 包中的原子类,例如 AtomicInteger
    • 使用 java.util.concurrent.locks 包中的锁
    • 使用线程安全的集合 ConcurrentHashMap
    • 使用 volatile 关键字,保证变量可见性(直接从内存读,而不是从线程 cache 读)

    2.volatile 实现原理

    在 JVM 底层 volatile 是采用“内存屏障”来实现的
    缓存一致性协议(MESI协议)它确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 CPU 在写数据时,如果发现操作的变量是共享变量,则会通知其他 CPU 告知该变量的缓存行是无效的,因此其他 CPU 在读取该变量时,发现其无效会重新从主存中加载数据
    3.synchronize 实现原理

    同步代码块是使用 monitorenter 和 monitorexit 指令实现的,同步方法(在这看不出来需要看 JVM 底层实现)依靠的是方法修饰符上的 ACC_SYNCHRONIZED 实现

    4.synchronized 与 lock 的区别

    synchronized 和 lock 的用法区别

    • synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized
      可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象
    • lock(显示锁):需要显示指定起始位置和终止位置。一般使用 ReentrantLock 类做为锁,多个线程中必须要使用一个
      ReentrantLock 类做为对象才能保证锁的生效。且在加锁和解锁处需要通过 lock() 和 unlock()
      显示指出。所以一般会在 finally 块中写 unlock() 以防死锁

    synchronized 和 lock 性能区别

    synchronized 是托管给 JVM 执行的,而 lock 是 Java 写的控制锁的代码。在 JDK 1.5 中,synchronize 是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用 Java 提供的 Lock 对象,性能更高一些。但是到了 JDK 1.6,发生了变化。synchronize 在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在 JDK 1.6 上 synchronize 的性能并不比 Lock 差

    synchronized 和 lock 机制区别

    synchronized 原始采用的是 CPU 悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁
    Lock 用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是 CAS 操作(Compare and Swap)
    由此面试官就可能下一个问题就接入到锁的问题上,当然也可能前面的问题回答不上,引入不到锁上,但是面试官想问时会主动问到吧

    5.说说悲观锁

    悲观锁悲观的认为每一次操作都会造成更新丢失问题,在每次查询时加上排他锁

    每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

    6.说说常用的 CAS 乐观锁

    CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试

    CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”这其实和乐观锁的冲突检查 + 数据更新的原理是一样的

    每次查询都不会造成更新丢失,利用版本字段控制

    7.说说 CAS ‘ABA’ 问题

    CAS 算法实现一个重要前提需要取出内存中某时刻的数据,而在下时刻比较并替换,那么在这个时间差类会导致数据的变化

    比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且 two 进行了一些操作变成了 B,然后 two 又将 V 位置的数据变成 A,这时候线程 one 进行 CAS 操作发现内存中仍然是 A,然后 one 操作成功。尽管线程 one 的 CAS 操作成功,但是不代表这个过程就是没有问题的,部分乐观锁的实现是通过版本号(version)的方式来解决 ABA 问题,乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行 +1 操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现 ABA 问题,因为版本号只会增加不会减少

    8.乐观锁的业务场景及实现方式

    乐观锁(Optimistic Lock):

    每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作
    比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量
    8.简单讲讲自旋锁

    自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区

    当一个线程 调用这个不可重入的自旋锁去加锁的时候没问题,当再次调用lock()的时候,因为自旋锁的持有引用已经不为空了,该线程对象会误认为是别人的线程持有了自旋锁
    使用了CAS原子操作,lock函数将owner设置为当前线程,并且预测原来的值为空。unlock函数将owner设置为null,并且预测值为当前线程。
    当有第二个线程调用lock操作时由于owner值不为空,导致循环一直被执行,直至第一个线程调用unlock函数将owner设置为null,第二个线程才能进入临界区。
    由于自旋锁只是将当前线程不停地执行循环体,不进行线程状态的改变,所以响应速度更快。但当线程数不停增加时,性能下降明显,因为每个线程都需要执行,占用CPU时间。如果线程竞争不激烈,并且保持锁的时间段。适合使用自旋锁

    题外

    本文章限于篇幅只放出了部分资料,近段时间正值找工作的最佳时间,本人将一些各大厂商的面试题和今年(2020)最新资料的收集,以下是部分资料截图(所有资料均已整合成文档,pdf压缩打包处理)。
    如果你需要全部的关于JAVA面试题和2020最新的资料可以点击这里来获取,暗号:qf

    在这里插入图片描述

    展开全文
  • java锁相关的思维导图整理 发出来是希望大家提出意见并一起纠错的,希望大家认真看看有没有什么缺的地方


    写在前面:
    本文是个人整理的锁相关知识点,分享出来 希望大家提出意见,少走弯路!
    最后附上画的思维导图!(大部分概念经过个人精简方便记忆,有补充意见评论提出)

    基本概念

    Java锁是什么

    锁(lock)或互斥(mutex)是一种同步机制,用于多线程环境下强制对资源的访问权限,旨在强制实施互斥排他,并发的控制策略

    锁开销(lock overhead)

    锁占用内存空间,cpu初始化和销毁锁,获取和释放锁的时间。程序用的锁越多,相应的开销越大

    锁竞争(lock contention)

    一个进程或线程试图获取另一个进程或线程持有的锁,就会发生竞争。锁粒度越小,发生锁竞争的可能性就越小

    死锁(deadlock)

    死锁的概念

    至少两个任务中的每一个都等待另一个任务持有的锁的情况

    死锁发生的条件

    1.互斥条件: 一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待
    2.请求与保持条件: 进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
    3.不可剥夺条件: 进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)
    4.循环等待条件: 即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路

    锁的种类

    1.公平锁/非公平锁(按申请顺序分类)

    公平锁: 线程获取锁的顺序和调用lock的顺序一样,FIFO(较少用到)
    公平锁实例:ReentrantLock(true)可实现公平锁

    非公平锁: 线程获取锁的顺序和调用lock的顺序无关,全凭运气(大多锁都为非公平锁,提高效率)
    非公平锁实例: ReenTrantLock默认是非公平锁。Synchronized只能是非公平锁
    优点:吞吐量大
    缺点:可能造成优先级反转或者饥饿现象

    2.共享锁/独享锁(按资源是否只能被一个资源持有分类)

    独享锁: 该锁一次只能被一个线程所持有
    实例:Synchronized、ReentranLock、ReenWriteLock的写锁

    共享锁: 该锁可以被多个线程所持有
    实例:ReenWriteLock的读锁

    3.互斥锁/读写锁(就是 共享锁/独享锁 的具体实现)

    互斥锁: ReentranLock,Synchronized

    读写锁: ReentrantReadWriteLock(其读锁是共享锁,其写锁是独享锁)

    4.乐观锁/悲观锁(按并发情况下资源分配策略分类)

    乐观锁: 认为一个数据的并发操作,是不会发生修改的,在更新数据的时候,会采用尝试更新而不直接加锁。(即不加锁策略,使用CAS判断,下面算法会提到)

    实例:CAS(Compare and Swap)算法

    使用场景:简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少)不加锁会带来大量的性能提升

    悲观锁: 认为对同一数据的并发操作一定会发生修改,所以采取加锁方式。在一个资源被分配到线程期间,其他线程只能等待,造成效率较低,但不会有线程安全问题

    实例:Synchronize关键字,Lock的三个实现类(ReentranLock以及ReentrantReadWriteLock类中的两个静态内部类ReadLock和WriteLock)

    使用场景:悲观锁适合写操作非常多的场景

    4.可重入锁(又名递归锁)

    可重入锁: 可重入锁又名递归锁,指的是线程在获得锁之后,再次获取该锁不需要阻塞,而是直接关联一次计数器增加重入次数

    实例:ReentrantLock,Synchronized

    好处:可一定程度避免死锁

    5.分段锁(对于ConcurrentHashMap的一种设计)

    实例:ConcurrentHashMap

    实现:在ConcurrentHashMap中当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入

    6.偏向锁/轻量级锁/重量级锁(针对Synchronized,锁的粒度逐渐加大)

    偏向锁: 指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。

    轻量级锁: 指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。

    重量级锁: 指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

    7.自旋锁

    自旋锁: 指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。

    相关算法

    CAS(Compare and Swap)算法(适用于多读场景,冲突一般较少)

    CAS实现: 包含三个参数CAS(V, E, N),V表示当前当前实际值,E表示预期值,N表示新值。仅当V等于E的时候,才会把V的值设置成N,否则不会执行任何操作(比较和替换是一个原子操作)。如果V值和E值不相等,则说明有其他线程修改过V值,当前线程什么都不做,最后返回当前V的真实值。CAS操作是抱着乐观的态度进行的,它总是认为自己可以成功的完成操作。当多个线程同时使用CAS操作一个变量时,只有一个会成功更新,其余都会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作

    相关问题:
    问题1: ABA问题:如果一个值原来是A,被其他线程变成了B,最后又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了
    解决方法: 使用版本号,在变量前面追加上版本号,每次变量更新的时候把版本号+1,那么A-B-A 就会变成1A-2B-3A(Java中AtomicStampedReference内部使用Pair来存储元素值及其版本号,主要用来解决ABA问题。)

    问题2: CAS导致自旋消耗:多个线程争夺同一个资源时,如果自旋一直不成功,将会一直占用CPU。
    解决方法: 破坏掉for死循环,当超过一定时间或者一定次数时,return退出

    问题3: CAS只能单变量:CAS的原子操作只能针对一个共享变量
    解决方法: 对多个变量操作,1. 可以加锁来解决。2 .封装成对象类解决。

    AQS(AbstractQueuedSynchronizer抽象队列同步器)

    实现: AQS的实现依赖内部的FIFO双向队列,如果当前线程竞争锁失败,那么AQS会把当前线程以及等待状态信息构造成一个Node加入到同步队列中,同时再阻塞该线程。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。
    操作方式:
    锁竞争添加节点:
    1.新的线程封装成Node节点追加到同步队列中,设置prev节点以及修改当前节点的前置节点的next节点指向自己
    2.通过CAS将tail重新指向新的尾部节点
    锁释放移除节点:
    1.修改head节点指向下一个获得锁的节点
    2.新的获得锁的节点,将prev的指针指向null
    资源共享方式: 独占与共享
    AQS更多内容可能放到并发章节详细展开

    面试题

    Synchronized横切面详解

    java源码层级: synchronized(对象)
    字节码层级: monitorenter,moniterexit(加锁,解锁,C++通过指针实现)
    JVM层级:(Hotspot的实现):在32位机系统里面,锁用三个bit做标记,其中一个bit表示是否为偏向锁,两个bit表示锁类型。
    2个bit的标志位:00(轻量级锁定),01(未锁定),10(重量级锁),11(GC标记)
    1个bit的偏向锁标志位:1为可偏向

    Synchronized升级过程: 首先线程自动获取锁,此时为偏向锁(无线线程冲突情况)。
    若此时被另一个线程所访问,则此锁就会升级为轻量级锁。其他线程会通过自旋尝试获取锁,不会阻塞,提高性能(有线程冲突情况)
    若此时等待线程自旋(CAS)超过十次,则此轻量级锁会升级为重量级锁,重量级锁会让其他请求的线程进入阻塞,性能降低(线程冲突严重情况)

    面试题1: 偏向锁一定能提高效率吗?
    可借鉴回答:分情况,当明确的知道有多个线程竞争的时候,锁升级的过程也会消耗资源,所以一开始就应该用重量级锁

    面试题2: 轻量级锁一定比重量级锁效率高吗?
    可借鉴回答:未必,当线程自旋的时候会消耗cpu资源,而重量级锁会把其它线程阻塞,不消耗cpu资源

    Synchronized和Lock的区别

    1.Lock是一个接口(jdk实现),而synchronized是Java中的关键字,synchronized是内置的语言实现(jvm实现)

    2.synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁

    3.Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断

    4.synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁

    5.通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。

    Synchronized和Lock的性能比较

    1.在高争用,高耗时的环境下Synchronized效率更高

    2.在低争用,低耗时的环境下,CAS效率更高

    3.Synchronized到重量级之后是等待队列,不消耗CPU

    4.CAS等待时间消耗CPU

    关于两者的性能比较:一切以实测为准!

    在这里插入图片描述

    展开全文
  • 俗话讲,3月不跳槽,5月徒伤悲,到了八九月,就只能惦记着年终奖,又害怕新机会鸡飞蛋打 :)今天主要内容是java的线程部分和java。1.什么是线程?进程和线程的关系是什么?线程可定义为进程内的一个执行单位,...

    9696551d217240723741bb57e88e4e6c.png

    俗话讲,3月不跳槽,5月徒伤悲,到了八九月,就只能惦记着年终奖,又害怕新机会鸡飞蛋打 :)

    今天主要内容是java的线程部分和java的锁。

    1.什么是线程?进程和线程的关系是什么?

    线程可定义为进程内的一个执行单位,或者定义为进程内的一个可调度实体。 在具有多线程机制的操作系统中,处理机调度的基本单位不是进程而是线程。

    一个进程可以有多个线程,而且至少有一个可执行线程。

    简单的说,进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。

    线程和进程的关系:

    线程是进程的一个组成部分.

    进程的多个线程都在进程地址空间活动.

    系统资源是分配给进程的,线程需要资源时,系统从进程的资源里分配给线程.

    计算机调度的基本单位是线程.

    线程上下文的切换比进程上下文切换要快很多

    进程切换时,涉及到当前进程的CPU环境的保存和新被调度运行进程的CPU环境的设置。

    线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。

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

    简单的说,加锁的就是线程安全的,不加锁的是线程不安全的

    线程安全:当多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

    线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

    如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

    线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

    3.什么是多线程?

    多线程就是多个线程同时运行或交替运行。

    如果是单核CPU则是顺序执行,也就是交替运行。

    如果是多核CPU,因为每个CPU有自己的运算器,所以在多个CPU中可以同时运行。

    4.为什么要有多线程?

    使用线程可以把占据长时间的程序中的任务放到后台去处理。

    用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。

    程序的运行速度可能加快。

    dc30074dc609dbac6e13d3b862c5e291.png

    5.Java多线程有哪几类

    用户线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程守护线程:运行在后台,为其他前台线程服务.一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作6、什么是多线程上下文切换

    多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。

    7.创建线程有几种不同的方式?

    有三种方式可以用来创建线程:

    继承Thread类实现Runnable接口应用程序可以使用Executor框架来创建线程池通常用实现Runnable接口这种方式创建线程,因为这不需要继承Thread类。

    8.Thread 类中的start() 和 run() 方法有什么区别?

    start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。

    当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。

    9.直接调用start()方法时和直接调用run()方法有什么区别?

    当我们new一个Thread,线程进入了新建状态;调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。

    start()会执行线程的相应准备工作,然后自动执行run()方法的内容,这是真正的多线程工作。

    而直接执行run()方法,会把run方法当成一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

    因此,调用start方法方可启动线程并使线程进入就绪状态,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

    10.对ThreadLocal的理解

    ThreadLocal是一个创建线程局部变量的类。通常情况下我们创建的变量,可以被多个线程访问并修改,通过ThreadLocal创建的变量只能被当前线程访问。因为ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

    简单说,ThreadLocal就是一种以空间换时间的做法。在每个Thread里面维护了一个ThreadLocal.ThreadLocalMap把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了.

    11.ThreadLocal内部实现

    ThreadLocal提供了set和get方法.

    set方法会先获取当前线程,然后用当前线程作为句柄,获取ThreadLocaMap对象,并判断该对象是否为空,如果为空则创建一个,并设置值,不为空则直接设置值。

    ThreadLocal并不会导致内存泄露,因为ThreadLocalMap中的key存储的是ThreadLocal实例的弱引用,因此如果应用使用了线程池,即便之前的线程实例处理完之后出于复用的目的依然存活,也不会产生内存泄露。

    12.什么是线程安全?

    当多个线程访问某个类时,不管运行时环境采用何种调度方式或者线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为。

    线程安全的核心是“正确性”,也就是说当多个线程访问某个类时,能够得到预期的结果,那么就是线程安全的。

    791f8d292b53b6f052f86f6067cfd8a0.png

    13、如何在两个线程间共享数据

    通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待。

    比如说:阻塞队列BlockingQueue就是为线程之间共享数据而设计的

    14、生产者消费者模型的作用是什么?

    提高效率:通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率,这是生产者消费者模型最重要的作用

    解耦:这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的关联少,耦合越少就越可以独自发展而不需要收到相互的制约

    15、java中的++操作符是线程安全的么?

    不是线程安全的操作。

    它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差

    展开全文
  • 作者:小李博客https://blog.csdn.net/xiaoliboke/article/details/80737119工作多年以及在面试中,我经常能体会到,有些面试者确实是认真努力工作,但坦白说表现出的能力水平却不足以通过面试,通常是两方面原因:1...
  • 2020 Java面试题最新(五锁机制篇)

    千次阅读 2020-02-10 17:03:42
    锁的原因都是由并发问题发生的,在此我只是写一些面试中可能会问到的问题以及问题的答案,并不是给大家深入的讲解锁机制 一般面试官问都是从一个点引入一个点的问问题,所以我就先从线程问题引入到锁问题 1.说说线程...
  • 那么为什么这个类是不安全的呢,因为方法1获得了ListHelp的并没有获得list的,导致,方法1中对list的先检查后执行操作不是满足原子性的。那么后面的代码即是最终完成该类是线程安全类的答案。 import java.util....
  • 悲观锁的实现往往依靠数据库提供的锁机制,即在数据库中,在对数据记录操作前给记录加排它锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁 1.2 乐观锁 乐观锁是相对于悲观锁来说的,它认为数据在...
  • 那么为什么这个类是不安全的呢,因为方法1获得了ListHelp的并没有获得list的,导致,方法1中对list的先检查后执行操作不是满足原子性的。那么后面的代码即是最终完成该类是线程安全类的答案。 import java....
  • 1.synchronized实现原理? (Lock)和 (synchronized)两种区别? synchronized可以保证...synchronized是用java的monitor机制来实现的,就是synchronized代码块或者方法进入及退出的时候会生成monitorenter跟monit...
  • Java基础 面象对象的特征:继承、封装、多态; 封装:是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对信息的操作和访问; 继承:多个类中存在...
  • java 多线程面试题

    2020-04-16 23:27:11
    参考 bat等大公司常考java多线程面试题 50个多线程面试题 全面了解Java中的15种概念及机制! 史上最详细Java多线程面试题及答案!
  • Java面试题79:redis数据淘汰机制.mp4 │ Java面试题80:java访问redis级redis集群?.mp4 │ Java面试题81:微信公众号分类和微信开发原理.mp4 │ Java面试题82:怎么把微信和业务平台进行绑定.mp4 │ Java面试题...
  • 考察点:锁机制 参考回答: 主要相同点:Lock能完成synchronized所实现的所有功能 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,...
  • 文章目录一、锁分类二、锁机制三、面试题 一、锁分类 二、锁机制 三、面试题
  • 下面我们就Java的常见面试题带来展示,大家也来看一看自己能否全部答出。1.synchronized作用于静态方法和非静态方法的区别非静态方法:给对象加锁(可以理解为给这个对象的内存上,注意 只是这...
  • Java基础面试题 1 jvm内存模型概述描述下常用的垃圾收集算法垃圾收集器机制 2 stringbuffer和stringbuilder的区别底层实现原理 3 concurrenthashmap底层实现和锁机制 4 arraylist与linklist的区别在遍历查找和增删改...
  • Java大数据秋招面试题

    2020-05-03 21:50:13
    以下为整理的自己秋招遇到的面试题; 主要是Java和大数据相关题型; 根据印象整理了下,有些记不起来了。 死锁、乐观、悲观 synchronized底层原理及膨胀机制 ReetrantLock底层原理,源码是如何实现公平和非公平...
  • 对整理的面试题总结一些简略的回答,深入的分析还是需要自己去研究 1 微服务的限流方案,和服务降级方案 分布式微服务架构下,某一个节点出现故障,会导致雪崩效应。分布式总体限流方案:利用redis,记录调用量,...
  • 不错的面试题4.从没有看到这么通俗易懂的sping的解析6. --》非安全 数据结构(map list 堆 栈),是因为1)其数据的操作方法,不是原子性的(多行代码,某个线程没有运行结束,其他线程进来了)2)另外就是多线程同时...
  • 30道java常见的面试题

    2019-03-29 11:17:09
    最近在忙着面试 总结了一些面试题,下面的是面试java常见的面试题 大部分都会问到的 1.hashmap底层? 2.Java进程中断怎么处理? 3.介绍下面向对象? 4.介绍下多态? 5.方法重载和重写? 6.这俩哪个属于多态? 7.说下多...
  • 虽说已经是金三银四末期了,但陆续来面试的Java程序员也不少...Java实现机制,使用场景分析ReentranLock 源码,设计原理,整体过程volatile 的实现原理AQS 的实现过程……如果你仔细观察的话,上面的面试题都是...
  • 以下内容为本人总结各位大神提供的面试题目,非原创 何谓悲观锁与乐观锁 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观...传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,
  • java面试题

    2020-05-21 15:32:19
    java最新面试题2020 一面 上来就写:两个有序链表,a中去除b中存在的元素 快排,堆排 javajava中字符串的连接方法及实现 项目设计模式 数据库 锁机制 double表示小数精度问题 数据库查找出一个学校每个班级的前...
  • Java基础面试题

    2020-12-08 22:32:18
    Java基础面试题 1. HashMap 和 HashTable 以及 CurrentHashMap 的区别 首先说下最大的区别,HashMap是线程非安全的,效率比较高;HashTable和CurrentHashMap是线程安全的,效率比HashMap差一点,但CurrentHashMap比...
  • 这篇文章主要介绍了2020Java面试题最新(五锁机制篇),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 锁的原因都是由并发问题发生的,在此我只是写一些面试中可能会问到的问题以及...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 318
精华内容 127
关键字:

java锁机制面试题

java 订阅