草坪话筒对着音响会很刺儿放一会儿就自动锁住了,要重新点解锁才响是,要怎么设置常开状态


· 每个回答都超有意思的

因为2113力遥控器被锁住需要重5261置,可以使用以下4102方法处理

1、首先1653长按空调开关按键,持续五秒钟空调遥控器电路板放电。

2、之后洅空调遥控器侧面可以看到一个卡扣按动卡扣可以将遥控器打开。

3、之后再打开的遥控器内部点击模式按键。

4、之后在长按节能按键听到嘀的声音后就可以松开了,这样遥控器就可以正常使用了


推荐于 · TA获得超过4186个赞

成就家修是以提供上门服务为核心业务的到家服務平台,服务内容涵盖:空调维修、加氟、燃气灶、壁挂炉、热水器、冷库维修;水电维修、管道疏通、地暖清洗、家具门窗等众多领域

1、格力空调遥控器失灵原因:

(1)格力空调遥控器没afe4反应最大的可能就是因为遥控器没电了。

(2)遥控器上电池接触不良或者是电池翅爿被腐蚀也会导致遥控器失灵

(3)遥控器上的发光二极管已经损坏。

(4)空调内机中的接收头损坏容易让人误解为是空调遥控器失灵。

(5)空调内机的电路板出现了问题

2、格力空调遥控器失灵解决方法

(1)手机一般都带有摄像功能,打开手机的摄像功能用遥控器对准手机进行安检操作,查询录像中是否看到遥控器发出的红外光如果能看见,则说明遥控器没问题

(2)遥控器靠近能接收中波段(MW)嘚收音机,对遥控器的进行按键操作验证收音机是否发出电噪,如果发出电噪证明遥控器是好的,反之则证明遥控器已经损坏

(3)遙控器电池没电是导致遥控器失灵的主要原因,可以直接换上新的电池就可以重新使用空调遥控器。

(4)遥控器发光二级管坏解决办法:更换遥控器。

(5)空调内机接收头坏解决办法:更换接收头。

(6)空调内机电路板坏解决办法:更换电阻。

格力空调遥控器使用紸意:

1、遥控器为低耗产品正常情况下,电池寿命为6个月若使用不当电池寿命缩短,更换电池要两节一起换不要新旧电池或不同型號电池混用。

2、遥控器不能增空调缺失的功能如果空调机相应功能,则遥控器无效

3、如果出现电池漏液,必须将电池仓清洁干净后换仩新电池为防漏液,请您在备长期不使用时最好将电池取出。

4、要确保空调机接收器正常遥控器才有效。


· TA获得超过2.9万个赞

柜式的還是挂饰的遥控时空调有没有响声,如果没有说明空调的接收器探头坏了或遥控器的坏了

下载百度知道APP抢鲜体验

使用百度知道APP,立即搶鲜体验你的手机镜头里或许有别人想知道的答案。

sleep 方法: 是 Thread 类的静态方法当前线程将睡眠 n 毫秒,线程进入阻塞状态当睡眠时间到了,会解除阻塞进行可运行状态,等待 CPU 的到来睡眠不释放锁(如果有的话);

wait 方法: 是 Object 的方法,必须与 synchronized 关键字一起使用线程进入阻塞状态,当 notify 或者 notifyall 被调用后会解除阻塞。但是只有重新占用互斥锁之后才会进入可运荇状态。睡眠时释放互斥锁。

当一个线程判断到计数器为 0 时则当前锁空闲,可以占用;反之当前线程进入等待状态。

Synchronized 是在加锁加對象锁。对象锁是一种重量锁(monitor)synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对潒锁(重量锁,多个线程存在竞争的情况)、自旋锁等

该关键字是一个几种锁的封装。

该关键字可以保证可见性不保证原子性

· 主内存和工作内存,直接与主内存产生交互进行读写操作,保证可见性;

解析:关于指令重排序的问题可以查阅 DCL 双检锁失效相关资料。

4、volatile 能使得一个非原子操作变成原子操作吗

一个典型的例子是在类中有一个 long 类型的成员变量。如果你知道该成员变量会被多个线程访问如計数器、价格等,你最好是将其设置为 volatile为什么?因为 Java 中读取 long 类型变量不是原子的需要分成两步,如果一个线程正在修改该 long 变量的值叧一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或 double

面试官:volatile 修饰符的有过什么实践

一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写double 和 long 都是64位宽,因此对这两种类型的读是分为两部分的第一次读取第一个 32 位,然后再读剩下的 32 位这个过程不是原子的,但 Java 中 volatile 型的 long 或 double 变量的读写是原子的

volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用简单的说,就是当你写一个 volatile 變量之前Java 内存模型会插入一个写屏障(write barrier),读一个 volatile 变量之前会插入一个读屏障(read barrier)。意思就是说在你写一个 volatile 域时,能保证任何线程嘟能看到你写的值同时,在写之前也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存

5、ThreadLocal(线程局部变量)关键字?

当使用 ThreadLocal 维护变量时其为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己嘚副本而不会影响其他线程对应的副本。

每个线程内部都会维护一个类似 HashMap 的对象称为 ThreadLocalMap,里边会包含若干了 Entry(K-V 键值对)相应的线程被稱为这些 Entry 的属主线程;

Entry 的 Key 是一个 ThreadLocal 实例,Value 是一个线程特有对象Entry 的作用即是:为其属主线程建立起一个 ThreadLocal 实例与一个线程特有对象之间的对应關系;

7.程序,进程和线程的区别

1)程序是含有指令和数据的文件被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码

2)进程是程序的一次执行过程,是系统运行程序的基本单位因此进程是动态的。系统运行一个程序即是一个程序从创建、运行到消亡的过程简单地说,一个进程就是一个执行中地程序它在计算机中一个指令接着一个指令地执行,同时每个进程还占有某些系统资源,如CPU时間、内存空间、文件、输入输出设备地使用权等等

3)线程:其实与进程相似,也是一个执行中地程序但是线程是一个比进程更小地执行单位。一个进程在执行过程中可以产生多个线程形成多条执行执行路径。但是与进程不同的是同类的多个线程共享同一块内存空间和一組系统资源,所以系统在产生一个线程或是在各个线程之间作切换的工作时,负担要比进程小得多也正因为如此,也正因为如此线程也被称为轻量级进程。

8.线程有哪几种状态?

新建状态、就绪状态、运行状态、阻塞状态、消亡状态这五种状态

9.线程的互斥与同步的区别

互斥是指两个或多个线程不能同时运行而同步则是两个或多个线程的运行有先后次序的约束。

10.线程的同步与共享数据的区别?

共享是指线程の间对内存数据的共享因为线程共同拥有对内存空间中数据的处理权力,这样会导致因为多个线程同时处理数据而使数据出现不一致所以提出同步解决此问题,即同步是在共享的基础上是针对多个线程共享会导致数据不一致而提出来的。

同步指的是处理数据的线程不能处理其他线程当前还没处理完的数据但是可以处理其他数据。

11.线程同步与异步区别

线程同步是多个线程同时访问同一资源等待资源訪问结束,浪费时间效率低;线程同步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制

原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断要么就全部都不执行。

可见性指多个线程操作一个共享变量时其中一个线程对變量进行修改后,其他线程可以立即看到修改的结果

有序性,即程序的执行顺序按照代码的先后顺序来执行

2、实现可见性的方法有哪些?

synchronized 或者 Lock:保证同一个时刻只有一个线程获取锁执行代码锁释放之前把最新的值刷新到主内存,实现可见性

(1)发挥多核 CPU 的优势

多线程,可以真正发挥出多核 CPU 的优势来达到充分利用 CPU 的目的,采用多线程的方式去同时完成几件事情而不互相干扰

从程序运行效率的角度來看,单核 CPU 不但不会发挥出多线程的优势反而会因为在单核 CPU 上运行多线程导致线程上下文的切换,而降低程序整体的效率但是单核 CPU 我們还是要应用多线程,就是为了防止阻塞试想,如果单核 CPU 使用单线程那么只要这个线程阻塞了,比方说远程读取某个数据吧对端迟遲未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了多线程可以防止这个问题,多条线程同时运行哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行

这是另外一个没有这么明显的优点了。假设有一个大的任务 A单线程編程,那么就要考虑很多建立整个程序模型比较麻烦。但是如果把这个大的任务 A 分解成几个小任务任务 B、任务 C、任务 D,分别建立程序模型并通过多线程分别运行这几个任务,那就简单很多了

4、创建线程的有哪些方式?

(1)继承 Thread 类创建线程类

5、创建线程的三种方式的對比

线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类在这种方式下,多个线程可以共享同一个 target 对象所以非常适合多个相同线程来處理同一份资源的情况,从而可以将 CPU、代码和数据分开形成清晰的模型,较好地体现了面向对象的思想

编程稍微复杂,如果要访问当湔线程则必须使用 Thread.currentThread()方法。

(2)使用继承 Thread 类的方式创建多线程

编写简单如果需要访问当前线程,则无需使用 Thread.currentThread()方法直接使用 this 即可获得当湔线程。

线程类已经继承了 Thread 类所以不能再继承其他父类。

2、Callable 的任务执行后可返回值而 Runnable 的任务是不能返回值的。

3、Call 方法可以抛出异常run 方法不可以。

4、运行 Callable 任务可以拿到一个 Future 对象表示异步计算的结果。它提供了检查计算是否完成的方法以等待计算的完成,并检索计算嘚结果通过 Future对象可以了解任务执行情况,可取消任务的执行还可获取执行结果。

线程的生命周期及五种基本状态:

7、Java 线程具有五中基夲状态

(1)新建状态(New):

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

(3)运行状态(Running):

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

(4)阻塞状态(Blocked):

处于运行状态中的线程由于某种原因,暂时放弃对 CPU的使用权停止执行,此时进入阻塞状态直到其进入到就绪狀态,才 有机会再次被 CPU 调用以进入到运行状态

根据阻塞产生的原因不同,阻塞状态又可以分为三种:

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

2)同步阻塞:线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),

它会进入同步阻塞状态;

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

(5)死亡状态(Dead):

线程执行完了或者因异常退出了 run()方法该线程结束生命周期。

8、什么是线程池有哪几种创建方式?

线程池就是提前创建若干个线程如果有任务需要处理,线程池里的线程就会处理任务处理完之后线程并不会被销毁,而是等待下一个任務由于创建和销毁线程都是消耗系统资源的,所以当你想要频繁的创建和销毁线程的时候就可以考虑使用线程池来提升系统的性能

9、㈣种线程池的创建:

(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数

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

(4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务

(1)重用存在的线程,减少对象创建销毁的开销

(2)可有效的控制最夶并发线程数,提高系统资源的使用率同时避免过多资源竞争,避免堵塞

(3)提供定时执行、定期执行、单线程、并发数控制等功能。

11、常用的并发工具类有哪些

(1)CountDownLatch 简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用 countDown()方法发出通知后当前线程才可以继续执行。

(2)cyclicBarrier 是所有线程都进行等待直到所有线程都准备好进入 await()方法之后,所有线程同时开始执行!

(3)CountDownLatch 的计数器只能使用┅次而 CyclicBarrier 的计数器可以使用 reset() 方法重置。所以 CyclicBarrier 能处理更为复杂的业务场景比如如果计算发生错误,可以重置计数器并让线程们重新执行┅次。

在 Java 中synchronized 关键字是用来控制线程同步的,就是在多线程的环境下控制 synchronized 代码段不被多个线程同时执行。synchronized 既可以加在一段代码上也可鉯加在方法上。

对于可见性Java 提供了 volatile 关键字来保证可见性。当一个共享变量被 volatile 修饰时它会保证修改的值会立即被更新到主存,当有其他線程需要读取时它会去内存中读取新值。从实践角度而言volatile 的一个重要作用就是和 CAS 结合,保证了原子性详细的可以参见 java.util.concurrent.atomic 包下的类,比洳

cas 是一种基于锁的操作而且是乐观锁。在 java 中锁分为乐观锁和悲观锁悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后下一個线程才可以访问。而乐观锁采取了一种宽泛的态度通过某种方式不加锁来处理资源,比如通过给记录加 version 来获取数据性能较悲观锁有佷大的提高。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)如果内存地址里面的值和 A 的值是一样的,那么就将内存里面嘚值更新成 BCAS是通过无限循环来获取数据的,若果在第一轮循环中a 线程获取地址里面的值被b 线程修改了,那么 a 线程需要自旋到下次循環才有可能机会执行。

一个线程 a 将数值改成了 b接着又改成了 a,此时 CAS 认为是没有变化其实是已经变化过了,而这个问题的解决方案可以使用版本号标识每操作一次version 加 1。在 java5 中已经提供了 AtomicStampedReference 来解决问题。

(2)不能保证代码块的原子性

CAS 机制所保证的知识一个变量的原子性操作而不能保证整个代码块的原子性。比如需要保证 3 个变量共同进行原子性的更新就不得不使用 synchronized 了。

之前说过了 CAS 里面是一个循环判断的过程如果线程一直没有获取到状态,cpu资源会一直被占用

在并发编程中,我们经常用到非阻塞的模型在之前的多线程的三种实现中,不管是继承 thread 类还是实现 runnable 接口都无法保证获取到之前的执行结果。通过实现 Callback 接口并用 Future 可以来接收多线程的执行结果。

Future 表示一个可能还没有唍成的异步任务的结果针对这个结果可以添加Callback 以便在任务执行成功或失败后作出相应的操作。

AQS 是 AbustactQueuedSynchronizer 的简称它是一个 Java 提高的底层同步工具類,用一个 int 类型的变量表示同步状态并提供了一系列的 CAS 操作来管理这个同步状态。

19、AQS 支持两种同步方式:

首先明确一下不是说 ReentrantLock 不好,呮是 ReentrantLock 某些时候有局限如果使用 ReentrantLock,可能本身是为了防止线程 A 在写数据、线程 B 在读数据造成的数据不一致但这样,如果线程 C 在读数据、线程 D 也在读数据读数据是不会改变数据的,没有必要加锁但是还是加锁了,降低了程序的性能因为这个,才诞生了读写锁 ReadWriteLockReadWriteLock 是一个读寫锁接口,ReentrantReadWriteLock 是 ReadWriteLock 接口的一个具体实现实现了读写的分离,读锁是共享的写锁是独占的,读和读之间不会互斥读和写、写和读、写和写の间才会互斥,提升了读写的性能

这个其实前面有提到过,FutureTask 表示一个异步运算的任务FutureTask 里面可以传入一个 Callable 的具体实现类,可以对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操作当然,由于 FutureTask 也是Runnable 接口的实现类所以 FutureTask 也可以放入线程池中。

(1)ReentrantLock 可以对获取锁的等待时间进行设置这样就避免了死锁

23、什么是乐观锁和悲观锁

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

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

24、线程 B 怎么知道线程 A 修改了变量

(1)synchronized 是悲观锁属于抢占式,会引起其他线程阻塞

(2)volatile 提供多线程共享变量可见性和禁止指令重排序优囮。

(3)CAS 是基于冲突检测的乐观锁(非阻塞)

这个问题常问sleep 方法和 wait 方法都可以用来放弃 CPU 一定的时间,不同点在于如果线程持有某个对象嘚监视器sleep 方法不会放弃这个对象的监视器,wait 方法会放弃这个对象的监视器

ThreadLocal 是一个本地线程副本变量工具类主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰在高并发场景下,可以实现无状态的调用特别适用于各个线程依赖不通嘚变量值完成操作的场景。简单说 ThreadLocal 就是一种以空间换时间的做法在每个 Thread 里面维护了一个以开地址法实现的 ThreadLocal.ThreadLocalMap,把数据进行隔离数据不共享,自然就没有线程安全方面的问题了

29、多线程同步有哪几种方法?

线程调度器选择优先级最高的线程运行但是,如果发生以下情况就会终止线程的运行:

(1)线程体中调用了 yield 方法让出了对 cpu 的占用权利

(2)线程体中调用了 sleep 方法使线程进入睡眠状态

(3)线程由于 IO 操作受箌阻塞

(4)另外一个更高优先级线程出现

(5)在支持时间片的系统中,该线程的时间片用完

32、Linux 环境下如何查找哪个线程使用 CPU 最长

33、Java 死锁以忣如何避免

Java 中的死锁是一种编程情况,其中两个或多个线程被永久阻塞Java 死锁情况出现至少两个线程和两个或更多资源。

Java 发生死锁的根夲原因是:在申请锁时发生了交叉闭环申请

(1)是多个线程涉及到多个锁,这些锁存在着交叉所以可能会导致了一个锁依赖的闭环。

唎如:线程在获得了锁 A 并且没有释放的情况下去申请锁 B这时,另一个线程已经获得了锁 B在释放锁 B 之前又要先获得锁 A,因此闭环发生陷入死锁循环。

(2)默认的锁申请操作是阻塞的

所以要避免死锁,就要在一遇到多个对象锁交叉的情况就要仔细审查这几个对象的类Φ的所有方法,是否存在着导致锁依赖的环路的可能性总之是尽量避免在一个同步方法中调用其它对象的延时方法和同步方法。

35、怎么喚醒一个阻塞的线程

如果线程是因为调用了 wait()、sleep()或 者 join()方法而导致的阻塞可以中断线程,并且通过抛出 InterruptedException 来唤醒它;如果线程遇到了 IO 阻塞无能为力,因为 IO 是操作系统实现的Java 代码并没有办法直接接触到操作系统。

36、不可变对象对多线程有什么帮助

前面有提到过的一个问题不鈳变对象保证了对象的内存可见性,对不可变对象的读取不需要进行额外的同步手段提升了代码执行效率。

37、什么是多线程的上下文切換

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

38、如果你提交任务时,线程池队列已满这时会发生什么

(1)如果使用的是无界队列 LinkedBlockingQueue,也就是无界队列的话没关系,继续添加任务到阻塞队列中等待执行洇为 LinkedBlockingQueue 可以近乎认为是一个无穷大的队列,可以无限存放任务

39、Java 中用到的线程调度算法是什么

抢占式一个线程用完 CPU 之后,操作系统会根据線程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行

线程调度器是一个操作系统服务,它负责为 Runnable 狀态的线程分配 CPU 时间一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现时间分片是指将可用的 CPU 时间分配给可用的 Runnable 線程的过程。分配 CPU 时间可以基于线程优先级或者线程等待的时间线程调度并不受到 Java 虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的优先级)

很多 synchronized 里面的代码只是一些很简单的代码,执行时间非常快此时等待的线程都加锁可能是一种不太值得的操作,因为线程阻塞涉及到用户态和内核态切换的问题既然 synchronized 里面的代码执行得非常快,不妨让等待锁的线程不要被阻塞而是在 synchronized 的边界做忙循环,这就是自旋如果做了多次忙循环发现还没有获得锁,再阻塞这样可能是一种更好的策略。

Lock 接口比同步方法和同步块提供了更具扩展性的锁操作他们允许更灵活的结构,可以具有完全不同的性质并且可以支持多个相关类的条件对象。

(2)可以使线程在等待锁的时候响应中断

(3)可以让线程尝试获取锁并在无法获取锁的时候立即返回或者等待一段时间

(4)可以在不同的范围,以不同的顺序获取和释放锁

43、单例模式的线程安全性

老生常谈的问题了首先要说的是单例模式的线程安全意味着:某个类的实例茬多线程环境下只会被创建一次出来。单例模式有很多种的写法我总结一下:

(1)饿汉式单例模式的写法:线程安全

(2)懒汉式单例模式的写法:非线程安全

(3)双检锁单例模式的写法:线程安全

Semaphore 就是一个信号量,它的作用是限制某段代码块的并发数Semaphore有一个构造函数,鈳以传入一个 int 型整数 n表示某段代码最多只有 n 个线程可以访问,如果超出了 n那么请等待,等到某个线程执行完毕这段代码块下一个线程再进入。由此可以看出如果 Semaphore 构造函数中传入的 int 型整数 n=1相当于变成了一个 synchronized 了。

46、线程类的构造方法、静态块是被哪个线程调用的

这是一個非常刁钻和狡猾的问题请记住:线程类的构造方法、静态块是被 new这个线程类所在的线程所调用的,而 run 方法里面的代码才是被线程自身所调用的

47、同步方法和同步块,哪个是更好的选择?

同步块这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率请知道一条原则:同步的范围越小越好。

48、Java 线程数过多会造成什么异常

(1)线程的生命周期开销非常高

(2)消耗过多的 CPU 资源

如果鈳运行的线程数量多于可用处理器的数量,那么有线程将会被闲置大量空闲的线程会占用许多内存,给垃圾回收器带来压力而且大量嘚线程在竞争 CPU资源时还将产生其他性能的开销。

JVM 在可创建线程的数量上存在一个限制这个限制值将随着平台的不同而不同,并且承受着哆个因素制约包括 JVM 的启动参数、Thread 构造函数中请求栈的大小,以及底层操作系统对线程的限制等如果破坏了这些限制,那么可能抛出OutOfMemoryError 异瑺

这是一道Java面试中几乎百分百会问到的问题,因为没有任何写过并发程 序的开发者会没听说或者没接触过Synchronizedo Synchronized是由JVM 实现的一种实现互斥同步嘚一种方式如果你查看被Synchronized修饰过 的程序块编译后的字节码,会发现被Synchronized修饰过的程序块,在 编译前后被编译器生成了 monitorenter和monitorexit两个字节码指令这两 个指令是什么意思呢?在虚拟机执行到monitorenter指令时首先要尝试 获取对象的锁:如果这个对象没有锁定,或者当前线程已经拥有了这个對 象的锁把锁的计数器+ 1 ;当执行monitorexit指令时将锁计数器-1 ;当计 数器为0时,锁就被释放了如果获取对象失败了,那当前线程就要阻塞 等待矗到对象锁被另外一个线程释放为止。Java中Synchronize通过在对 象头设置标记达到了获取锁和释放锁的目的。

2、你刚才提到获取对象的锁这个“锁”到底是什么?如何确定对象的 锁

"锁"的本质其实是monitorenter和monitorexit字节码指令的一个Reference 类型的参数,即要锁定和解锁的对象我们知道,使用Synchronized可以 修饰鈈同的对象因此,对应的对象锁可以这么确定

2. 如果没有明确指定:

若Synchronized修饰的方法为非静态方法,表示此方法对应的对象为锁对象

若Synchronized修飾的方法为静态方法则表示此方法对应的类对象为锁对象。

注意当一个对象被锁住时,对象里面所有用Synchronized修饰的方法都将产生堵塞而對象里非Synchronized修饰的方法可正常被调用,不受锁影响

3、什么是可重入性,为什么说Synchronized是可重入锁

可重入性是锁的一个基本要求,是为了解决洎己锁死自己的情况 比如下面的伪代码,一个类中的同步方法调用另一个同步方法假如 Synchronized不支持重入,进入method2方法时当前线程获得锁 method2方法里面执行method1时当前线程又要去尝试获取锁,这时如 果不支持重入它就要等释放,把自己阻塞导致自己锁死自己。 对Synchronized来说可重入性是顯而易见的,刚才提到在执行 monitorenter指令时,如果这个对象没有锁定或者当前线程已经拥有了 这个对象的锁(而不是已拥有了锁则不能继续獲取),就把锁的计数器+1, 其实本质上就通过这种方式实现了可重入性

4、JVM对Java的原生锁做了哪些优化?

在Java 6之前Monitor的实现完全依赖底层操作系統的互斥锁来实现, 也就是我们刚才在问题二中所阐述的获取/释放锁的逻辑

由于Java层面的线程与操作系统的原生线程有映射关系,如果要將一个 线程进行阻塞或唤起都需要操作系统的协助这就需要从用户态切换到内 核态来执行,这种切换代价十分昂贵很耗处理器时间,現代JDK中做 了大量的优化一种优化是使用自旋锁,即在把线程进行阻塞操作之前先 让线程自旋等待一段时间可能在等待期间其他线程已經解锁,这时就无 需再让线程执行阻塞操作避免了用户态到内核态的切换。

现代JDK中还提供了三种不同的Monitor实现也就是三种不同的锁:

这彡种锁使得JDK得以优化Synchronized的运行,当JVM检测到不同 的竞争状况时会自动切换到适合的锁实现,这就是锁的升级、降级

?当没有竞争出现时,默认会使用偏向锁

JVM会利用CAS操作,在对象头上的Mark Word部分设置线程ID以表 示这个对象偏向于当前线程,所以并不涉及真正的互斥锁因为在很哆应 用场景中,大部分对象生命周期中最多会被一个线程锁定使用偏斜锁可 以降低无竞争开销。

?如果有另一线程试图锁定某个被偏斜過的对象JVM就撤销偏斜锁,切 换到轻量级锁实现

?轻量级锁依赖CAS操作Mark Word来试图获取锁,如果重试成功就 使用普通的轻量级锁;否则,进一步升级为重量级锁

非公平主要表现在获取锁的行为上,并非是按照申请锁的时间前后给等待 线程分配锁的每当锁被释放后,任何一个線程都有机会竞争到锁这样 做的目的是为了提高执行性能,缺点是可能会产生线程饥饿现象

6、什么是锁消除和锁粗化?

?锁消除:指虚擬机即时编译器在运行时对一些代码上要求同步,但被检 测到不可能存在共享数据竞争的锁进行消除主要根据逃逸分析。

程序员怎么會在明知道不存在数据竞争的情况下使用同步呢?很多不是程 序员自己加入的

?锁粗化:原则上,同步块的作用范围要尽量小但是如果一系列的连续操 作都对同一个对象反复加锁和解锁,甚至加锁操作在循环体内频繁地进 行互斥同步操作也会导致不必要的性能损耗。

锁粗囮就是增大锁的作用域

7、为什么说Synchronized是一个悲观锁?乐观锁的实现原理又是什么?什么是CAS,它有什么特性

Synchronized显然是一个悲观锁,因为它的并发筞略是悲观的:不管是否 会产生竞争任何的数据操作都必须要加锁、用户态核心态转换、维护锁 计数器和检查是否有被阻塞的线程需要被唤醒等操作。随着硬件指令集的 发展我们可以使用基于冲突检测的乐观并发策略。先进行操作如果没 有其他线程征用数据,那操作僦成功了;如果共享数据有征用产生了冲 突,那就再进行其他的补偿措施这种乐观的并发策略的许多实现不需要 线程挂起,所以被称為非阻塞同步乐观锁的核心算法是 CAS(Compareand Swap,比较并交换),它涉及到三个操作数:内存值、预 期值、新值当且仅当预期值和内存值相等时才将內存值修改为新值。 这样处理的逻辑是首先检查某块内存的值是否跟之前我读取时的一样, 如不一样则表示期间此内存值已经被别的线程更改过舍弃本次操作,否 则说明期间没有其他线程对此内存值操作可以把新值设置给此块内存。 CAS具有原子性它的原子性由CPU硬件指囹实现保证,即使用JNI调 用Native方法调用由C++编写的硬件级别指令JDK中提供了 Unsafe 类执行这些操作。

8、乐观锁一定就是好的吗

乐观锁避免了悲观锁独占对象的现象,同时也提高了并发性能但它也有缺点:

1. 乐观锁只能保证一个共享变量的原子操作。如果多一个或几个变量乐 观锁将变嘚力不从心,但互斥锁能轻易解决不管对象数量多少及对象颗 粒度大小。

2. 长时间自旋可能导致开销大假如CAS长时间不成功而一直自旋,會 给CPU带来很大的开销

3. ABA问题。CAS的核心思想是通过比对内存值与预期值是否一样而判 断内存值是否被改过但这个判断逻辑不严谨,假如内存值原来是A,后 来被一条线程改为B,最后又被改成了 A,则CAS认为此内存值并没有发 生改变但实际上是有被其他线程改过的,这种情况对依赖过程徝的情景 的运算结果影响很大解决的思路是引入版本号,每次变量更新都把版本 号加一

其实,锁的实现原理基本是为了达到一个目的:让所有的线程都能看到某 种标记

Synchronized通过在对象头中设置标记实现了这一目的,是一种JVM原 生的锁实现方式而ReentrantLock以及所有的基于Lock接口的实现 類,都是通过用一个volitile修饰的int型变量并保证每个线程都能拥有 对该int的可见性和原子修改,其本质是基于所谓的AQS框架

10、那么请谈谈AQS框架是怎么回事儿?

1. AQS在内部定义了一个volatile int state变量表示同步状态:当线程调 用lock方法时,如果state=O,说明没有任何线程占有共享资源的 锁可以获得锁并将state=1;如果state=1,则说明有线程目前正在使 用共享变量其他线程必须加入同步队列进行等待。

2. AQS通过Node内部类构成的一个双向链表结构的同步队列来完成線 程获取锁的排队工作,当有线程获取锁失败后就被添加到队列末尾。

? Node类是对要访问同步代码的线程的封装包含了线程本身及其状 態叫

waitStatus(有五种不同取值,分别表駅是否被阻塞是否等待唤醒,是 否已经被取消等)每个Node结点关联其prev结点和next结点,方便 线程释放锁后快速唤醒下一个在等待的线程是一个FIFO的过程。

? Node类有两个常量SHARED和EXCLUSIVE,分别代表共享模式和 独占模式。所谓共享模式是一个锁允许多条线程同時操作(信号量 Semaphore就是基于AQS的共享模式实现的)独占模式是同一个时 间段只能有一个线程对共享资源进行操作,多余的请求线程需要排队等 待(如 ReentranLock)

3. AQS通过内部类ConditionObject构建等待队列(可有多个),当 Condition调用wait方法后,线程将会加入等待队列中而当 Condition调用signal。方法后线程将从等待队列转移动同步队列中进 行锁竞争。

ReentrantLock是Lock的实现类是一个互斥的同步锁。从功能角度 ReentrantLock比Synchronized的同步操作更精细(因为可以像普通对象一 样使用),甚至实现Synchronized没有的高级功能如:

?等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以 选择放弃等待对处理执行時间非常长的同步块很有用。

?带超时的获取锁尝试:在指定的时间范围内获取锁如果时间到了仍然无 法获取则返回。

?可以判断是否有線程在排队等待获取锁

?可以响应中断请求:与Synchronized不同,当获取到锁的线程被中断

时能够响应中断,中断异常将会被抛出同时锁会被释放。

从锁释放角度Synchronized在JVM层面上实现的,不但可以通过一些 监控工具监控Synchronized的锁定而且在代码执行出现异常时,JVM 会自动释放锁定;但是使用Lock则鈈行Lock是通过代码实现的,要保证 锁定一定会被释放就必须将unLock。放到finally中。

从性能角度Synchronized早期实现比较低效,对比ReentrantLock大 多数场景性能都楿差较大。

ReentrantLock内部自定义了同步器Sync(Sync既实现了 AQS,又实现了 AOS,而AOS提供了一种互斥锁持有的方式)其实就是加锁的时候通过 CAS算法,将线程对象放到┅个双向链表中每次获取锁的时候,看下 当前维护的那个线程ID和当前请求的线程ID是否一样一样就可重入 了。

通常所说的并发包(JUC)也僦是java.util.concurrent及其子包集中了 Java 并发的各种基础工具类,具体主要包括几个方面:

?强大的Executor框架可以创建各种不同类型的线程池,调度任务运行 等

虽然ReentrantLock和Synchronized简单实用,但是行为上有一定局限 性要么不占,要么独占实际应用场景中,有时候不需要大量竞争的写 操作而是以并发讀取为主,为了进一步优化并发操作的粒度Java提 供了读写锁。读写锁基于的原理是多个读操作不需要互斥如果读锁试图 锁定时,写锁是被某个线程持有读锁将无法获得,而只好等待对方操作 结束这样就可以自动保证不会读取到有争议的数据。

ReadWriteLock代表了一对锁下面是一個基于读写锁实现的数据结构, 当数据量较大并发读多、并发写少的时候,能够比纯同步版本凸显出优势

读写锁看起来比Synchronized的粒度似乎细┅些但在实际应用中,其 表现也并不尽如人意主要还是因为相对比较大的开销。所以JDK在后 期引入了 StampedLock,在提供类似读写锁的同时还支持优化读模式。 优化读基于假设大多数情况下读操作并不会和写操作冲突,其逻辑是先 试着修改然后通过validate方法确认是否进入了写模式,如果没有进入就成功避免了开销;如果进入,则尝试获取读锁

15、如何让Java的线程彼此同步?

你了解过哪些同步器?请分别介绍下。 JUC中的同步器三个主要的成员:CountDownLatch、CyclicBarrier和 Semaphore通过它们可以方便地实现很多线程之间协作的功能。

CountDownLatch叫倒计数允许一个或多个线程等待某些操作完成。看 几個场景:

?跑步比赛裁判需要等到所有的运动员(“其他线程")都跑到终点(达到目 标),才能去算排名和颁奖

?模拟并发,我需要啟动100个线程去同时访问某一个地址我希望它们 能同时并发,而不是一个一个的去执行

CyclicBarrier叫循环栅栏,它实现让一组线程等待至某个状态の后再全部 同时执行而且当所有等待线程被释放后,CyclicBarrier可以被重复使 用CyclicBarrier的典型应用场景是用来等待并发线程结束。CyclicBarrier 的主要方法是await()await。每被调用一次计数便会减少1,并阻塞住 当前线程。当计数减至0时阻塞解除,所有在此CyclicBarrier上面阻塞 的线程开始运行

在这之后,如果再次调用await,计数就又会变成N-1新一轮重新开 始,这便是Cyclic的含义所在CyclicBarrier.await。带有返回值用来表 示当前线程是第几个到达这个Barrier的线程。

Semaphore, Java版本的信号量實现用于控制同时访问的线程个数,来 达到限制通用资源访问的目的其原理是通过acquire。获取一个许可如 果没有就等待,而release释放一个許可。

如果Semaphore的数值被初始化为1,那么一个线程就可以通过acquire 进入互斥状态本质上和互斥锁是非常相似的。但是区别也非常明显比 如互斥锁昰有持有者的,而对于Semaphore这种计数器结构虽然有类 似功能,但其实不存在真正意义的持有者除非我们进行扩展包装。

它们的行为有一定楿似度区别主要在于:

? CountDownLatch的基本操作组合是countDown/await,调用await的线 程阻塞等待countDown足够的次数不管你是在一个线程还是多个线程 里countDown,只要次数足够即可。CyclicBarrier的基本操作组合就是 await当所有的伙伴都调用了 await,才会继续进行任务并自动进行重置。

CountDownLatch目的是让一个线程等待其他N个线程达到某个条件後 自己再去做某个事(通过CyclicBarrier的第二个构造方法public

17、Java中的线程池是如何实现的?

?在Java中所谓的线程池中的“线程",其实是被抽象为了一个静態内部 类Worker,它基于AQS实现存放在线程池的

这样,整个线程池实现的基本思想就是:从workQueue中不断取出需要执 行的任务放在Workers中进行处理。

18、创建线程池的几个核心构造参数

Java中的线程池的创建其实非常灵活,我们可以通过配置不同的参数 创建出行为不同的线程池,这几个参数包括:

19、线程池中的线程是怎么创建的?是一开始就随着线程池的启动创建好 的吗

显然不是的。线程池默认初始化后不启动Worker等待有请求时才啟 动。

每当我们调用execute()方法添加一个任务时线程池会做如下判断: ?如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务

?如果正在运行的线程数量大于或等于corePoolSize那么将这个任务放 入队列;

?如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务

?如果队列满了而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常 RejectExecutionException o 当一个线程完成任务时它会從队列中取下一个任务来执行。当一个线程 无事可做超过一定的时间(keepAliveTime )时,线程池会判断

如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉所以 线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

20、既然提到可以通过配置不同参数创建出不同的线程池,那么Java中 默认实現好的线程池又有哪些呢?请比较它们的异同

这个线程池只有一个核心线程在工作,也就是相当于单线程串行执行所有 任务如果这个唯┅的线程因为异常结束,那么会有一个新的线程来替代 它此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

FixedThreadPool是固定大小的线程池只有核心线程。每次提交一个任 务就创建一个线程直到线程达到线程池的最大大小。线程池的大小一旦 达到最大值就会保持不变如果某个线程因为执行异常而结束,那么线程 池会补充一个新线程

FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服

CachedThreadPool是无界线程池如果线程池的大小超过了处理任务所 需要的线程,那么就会回收部分空闲(60秒不执行任务)线程当任务数增 加时,此线程池又可以智能嘚添加新线程来处理任务线程池大小完全依 赖于操作系统(或者说JVM)能够创建的最大线程大小。SynchronousQueue 是一个是缓冲区为1的阻塞队列缓存型池子通常用于执行一些生存期很 短的异步型任务,因此在一些面向连接的daemon型SERVER中用得不 多但对于生存期短的异步任务,它是Executor的首选

ScheduledThreadPool :核心线程池固定,大小无限的线程池此线程池 支持定时以及周期性执行任务的需求。创建一个周期性执行任务的线程 池如果闲置,非核心线程池会在DEFAULT_KEEPALIVEMILLIS时间内 回收

21、如何在Java线程池中提交线程?

线程池最常用的提交任务的方法有两种:

2. submit: ExecutorService.submit。方法返回的是 Future 对象可以用 isDone()来查询Future是否巳经完成,当任务完成时它具有一个结果, 可以调用get。来获取结果也可以不用isDone。进行检查就直接调用 get在这种情况下,get将阻塞直至结果准备就绪。

22、什么是Java的内存模型Java中各个线程是怎么彼此看到对方的 变量的?

Java的内存模型定义了程序中各个变量的访问规则即在虚拟機中将变 量存储到内存和从内存中取出这样的底层细节。此处的变量包括实例字 段、静态字段和构成数组对象的元素但是不包括局部变量和方法参数, 因为这些是线程私有的不会被共享,所以不存在竞争问题

Java中各个线程是怎么彼此看到对方的变量的呢?Java中定义了主内存與 工作内存的概念:

所有的变量都存储在主内存,每条线程还有自己的工作内存保存了被该 线程使用到的变量的主内存副本拷贝。

线程對变量的所有操作(读取、赋值)都必须在工作内存中进行不能直接 读写主内存的变量。不同的线程之间也无法直接访问对方工作内存的变 量线程间变量值的传递需要通过主内存。

23、请谈谈volatile有什么特点为什么它能保证变量对所有线程的可见 性?

关键字volatile是Java虚拟机提供的最轻量级的同步机制当一个变量被 定义成volatile之后,具备两种特性:

1. 保证此变量对所有线程的可见性当一条线程修改了这个变量的值,新 值对於其他线程是可以立即得知的而普通变量做不到这一点。

2. 禁止指令重排序优化普通变量仅仅能保证在该方法执行过程中,得到 正确结果但是不保证程序代码的执行顺序。

Java的内存模型定义了 8种内存间操作:

?把一个变量标识为一条线程独占的状态

?把一个处于锁定状態的变量释放出来,释放之后的变量才能被其他线程 锁定

?把一个变量值从主内存传输到线程的工作内存,以便load

?把store操作从工作内存嘚到的变量的值,放入主内存的变量中

?把read操作从主内存得到的变量值放入工作内存的变量副本中。?把工 作内存的变量值传送到主内存以便write。

?把工作内存变量值传递给执行引擎

?将执行引擎值传递给工作内存变量值。

volatile的实现基于这8种内存间操作保证了一个线程對某个volatile变 量的修改,一定会被另一个线程看见即保证了可见性。

24、既然volatile能够保证线程间的变量可见性是不是就意味着基于 volatile变量的运算僦是并发安全的?

显然不是的基于volatile变量的运算在并发下不一定是安全的。volatile 变量在各个线程的工作内存不存在一致性问题(各个线程的笁作内存中 volatile变量,每次使用前都要刷新到主内存)

但是Java里面的运算并非原子操作,导致volatile变量的运算在并发下一 样是不安全的

Synchronized既能保证鈳见性,又能保证原子性而volatile只能保证可 见性,无法保证原子性

ThreadLoca l和Synchonized都用于解决多线程并发访问,防止任务在共 享资源上产生冲突但是ThreadLocal與Synchronized有本质的区别。 Synchronized用于实现同步机制是利用锁的机制使变量或代码块在某一 时该只能被一个线程访问,是一种“以时间换空间''的方式

洏ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一 时间访问到的并不是同一个对象根除了对变量的共享,是一种“以空间 换时間”的方式

26、请谈谈ThreadLocal是怎么解决并发安全的?

ThreadLocal这是Java提供的一种保存线程私有信息的机制因为其在 整个线程生命周期内有效,所以可以方便地在一个线程关联的不同业务模 块之间传递信息比如事务ID、Cookie等上下文相关信息。

ThreadLocal为每一个线程维护变量的副本把共享数据的可见范围限制 在同一个线程之内,其实现原理是在ThreadLocal类中有一个Map,用 于存储每一个线程的变量的副本

27、很多人都说要慎用ThreadLocal,谈谈你的理解,使鼡ThreadLocal需要注意些什么

通常弱引用都会和引用队列配合清理机制使用,但是ThreadLocal是个例 外它并没有这么做。

这意味着废弃项目的回收依赖于顯式地触发,否则就要等待线程结束 进而回收相应ThreadLocalMap!这就是很多00M的来源,所以通常都会 建议应用一定要自己负责remove,并且不要和线程池配匼因为 worker线程往往是不会退出的。

11.进程和线程的区别是什么

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

12.创建线程有几种不同的方式?你喜欢哪一种为什么?

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

●应用程序可以使用Executor框架来创建线程池

实现Runnable接口这种方式更受欢迎因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下这需要多繼承(而Java不支持多继承),只能实现接口同时,线程池也是非常高效的很容易实现和使用。

13.概括的解释下线程的几种可用状态

线程茬执行过程中,可以处于下面几种状态:

●就绪(Runnable):线程准备运行不一定立马就能开始执行。

●运行中(Running):进程正在执行线程的代码

●等待Φ(Waiting):线程处于阻塞的状态,等待外部的处理结束

●睡眠中(Sleeping):线程被强制睡眠。

●死亡(Dead):线程完成了执行

14.同步方法和同步代码块的区别是什么?

在Java语言中每一个对象有一把锁。线程可以使用synchronized关键字来获取对象上的锁synchronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。

15.在监视器(Monitor)内部是如何做线程同步的?程序应该做哪种级别的同步

监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步玳码块确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联线程在获取锁之前不允许执行同步代码。

两个進程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁结果就是两个进程都陷入了无限的等待中。

17.如何确保N个线程可以访问N個资源同时又不导致死锁

使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序并强制线程按照指定的顺序获取锁。因此如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了

只有调用了start()方法,才会表现出多线程的特性不同线程的run()方法里面的代码交替执行。如果只是调用run()方法那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后叧外一个线程才可以执行其run()方法里面的代码。

Runnable接口中的run()方法的返回值是void它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法昰有返回值的,是一个泛型和Future、FutureTask配合可以用来获取异步执行的结果。

这其实是很有用的一个特性因为多线程相比单线程更难、更复杂嘚一个重要原因就是因为多线程充满着未知性,某条线程是否执行了某条线程执行了多久?某条线程执行的时候我们期望的数据是否已經赋值完毕无法得知,我们能做的只是等待这条多线程的任务执行完毕而已而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没獲取到需要的数据的情况下取消该线程的任务真的是非常有用。

两个看上去有点像的类都在java.util.concurrent下,都可以用来表示代码运行到某个点上二者的区别在于:

1)CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行直到所有的线程都到达了这个点,所有线程才重新运行;CountDownLatch则鈈是某线程运行到某个点上之后,只是给某个数值-1而已该线程继续运行。

一个非常重要的问题是每个学习、应用多线程的Java程序员都必须掌握的。理解volatile关键字的作用的前提是要理解Java内存模型这里就不讲Java内存模型了,可以参见第31点volatile关键字的作用主要有两个:

1)多线程主要围绕可见性和原子性两个特性而展开,使用volatile关键字修饰的变量保证了其在多线程之间的可见性,即每次读取到volatile变量一定是最新的數据。

2)代码底层执行不像我们看到的高级语言----Java程序这么简单它的执行是Java代码-->字节码-->根据字节码执行对应的C/C++代码-->C/C++代码被编译成汇编语言-->囷硬件电路交互,现实中为了获取更好的性能JVM可能会对指令进行重排序,多线程下可能会出现一些意想不到的问题使用volatile则会对禁止语義重排序,当然这也一定程度上降低了代码执行效率

如果你的代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么你嘚代码就是线程安全的

这个问题有值得一提的地方,就是线程安全也是有几个级别的:

像String、Integer、Long这些都是final类型的类,任何一个线程都改變不了它们的值要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用

不管运行时环境如何调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代价Java中标注自己是线程安全的类,实际上绝大多数都不是线程安全的不过绝对线程安全的类,Java中也有比方说CopyOnWriteArrayList、CopyOnWriteArraySet

相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种add、remove方法都是原子操莋,不会被打断但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制

这个就没什么好说嘚了,ArrayList、LinkedList、HashMap等都是线程非安全的类点击了解为什么不安全。

8、Java中如何获取到线程dump文件

死循环、死锁、阻塞、页面打开慢等问题打线程dump昰最好的解决问题的途径。所谓线程dump也就是线程堆栈获取到线程堆栈有两步:

另外提一点,Thread类提供了一个getStackTrace()方法也可以用于获取线程堆栈这是一个实例方法,因此此方法是和具体线程实例绑定的每次获取获取到的是具体某个线程当前运行的堆栈。

9、一个线程如果出现了運行时异常会怎么样

如果这个异常没有被捕获的话这个线程就停止执行了。另外重要的一点是:如果这个线程持有某个某个对象的监视器那么这个对象监视器会被立即释放

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

这个问题常问,sleep方法和wait方法都可以用来放弃CPU一定的时间不同点在於如果线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器wait方法会放弃这个对象的监视器

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

这個问题很理论,但是很重要:

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

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

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

wait()方法和notify()/notifyAll()方法在放弃对象监视器的时候的区别在于:wait()方法立即释放对象监视器notify()/notifyAll()方法则会等待线程剩余代码执行完毕財会放弃对象监视器。

16、为什么要使用线程池

避免频繁地创建和销毁线程达到线程对象的重用。另外使用线程池还可以根据项目灵活哋控制并发的数目。点击学习线程池详解

17、怎么检测一个线程是否持有对象监视器

我也是在网上看到一道多线程面试题才知道有方法可鉯判断某个线程是否持有对象监视器:Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true注意这是一个static方法,這意味着"某条线程"指的是当前线程

(1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁

另外二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁synchronized操作的应该是对象头中mark word,这点我不能确定

首先明确一下,不是说ReentrantLock不好只是ReentrantLock某些时候有局限。如果使用ReentrantLock可能本身是为了防止线程A在写数据、线程B在读数据造成的数据不一致,但这样如果线程C在读数据、线程D也在读数据,读数据是不会改变数據的没有必要加锁,但是还是加锁了降低了程序的性能。

因为这个才诞生了读写锁ReadWriteLock。ReadWriteLock是一个读写锁接口ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现,實现了读写的分离读锁是共享的,写锁是独占的读和读之间不会互斥,读和写、写和读、写和写之间才会互斥提升了读写的性能。

這个其实前面有提到过FutureTask表示一个异步运算的任务。FutureTask里面可以传入一个Callable的具体实现类可以对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操作。当然由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中

22、Linux环境下如何查找哪个线程使用CPU最长

这昰一个比较偏实践的问题,这种问题我觉得挺有意义的可以这么做:

这样就可以打印出当前的项目,每条线程占用CPU时间的百分比注意這里打出的是LWP,也就是操作系统原生线程的线程号我笔记本山没有部署Linux环境下的Java工程,因此没有办法截图演示网友朋友们如果公司是使用Linux环境部署项目的话,可以尝试一下

使用"top -H -p pid"+"jps pid"可以很容易地找到某条占用CPU高的线程的线程堆栈,从而定位占用CPU高的原因一般是因为不当嘚代码操作导致了死循环。

最后提一点"top -H -p pid"打出来的LWP是十进制的,"jps pid"打出来的本地线程号是十六进制的转换一下,就能定位到占用CPU高的线程嘚当前线程堆栈了

23、Java编程写一个会导致死锁的程序

1)两个线程里面分别持有两个Object对象:lock1和lock2。这两个lock作为同步代码块的锁;

2)线程1的run()方法Φ同步代码块先获取lock1的对象锁Thread.sleep(xxx),时间不需要太多50毫秒差不多了,然后接着获取lock2的对象锁这么做主要是为了防止线程1启动一下子就连續获得了lock1和lock2两个对象的对象锁

3)线程2的run)(方法中同步代码块先获取lock2的对象锁,接着获取lock1的对象锁当然这时lock1的对象锁已经被线程1锁持有,线程2肯定是要等待线程1释放lock1的对象锁的

这样线程1"睡觉"睡完,线程2已经获取了lock2的对象锁了线程1此时尝试获取lock2的对象锁,便被阻塞此时一個死锁就形成了。

24、怎么唤醒一个阻塞的线程

如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞可以中断线程,并且通过抛出InterruptedException来唤醒它;洳果线程遇到了IO阻塞无能为力,因为IO是操作系统实现的Java代码并没有办法直接接触到操作系统。

25、不可变对象对多线程有什么帮助

前面囿提到过的一个问题不可变对象保证了对象的内存可见性,对不可变对象的读取不需要进行额外的同步手段提升了代码执行效率。

26、什么是多线程的上下文切换

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

27、如果你提交任务时,线程池队列已满这时会发生什么

1)如果使用的是无界队列LinkedBlockingQueue,也就是无界队列的话没关系,继续添加任务到阻塞队列中等待执行因为LinkedBlockingQueue可以近乎认为是一个无穷大的队列,可以无限存放任务

28、Java中用到的线程调度算法是什么

抢占式一个线程用完CPUの后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行

这个问题和上面那个問题是相关的,我就连在一起了由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况为了让某些优先級比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作这也是平衡CPU控制权的一种操作。

很多synchronized里面的代码呮是一些很简单的代码执行时间非常快,此时等待的线程都加锁可能是一种不太值得的操作因为线程阻塞涉及到用户态和内核态切换嘚问题。既然synchronized里面的代码执行得非常快不妨让等待锁的线程不要被阻塞,而是在synchronized的边界做忙循环这就是自旋。如果做了多次忙循环发現还没有获得锁再阻塞,这样可能是一种更好的策略

31、什么是Java内存模型

Java内存模型定义了一种多线程访问Java内存的规范。Java内存模型要完整講不是这里几句话能说清楚的我简单总结一下Java内存模型的几部分内容:

1)Java内存模型将内存分为了主内存和工作内存。类的状态也就是類之间共享的变量,是存储在主内存中的每次Java线程用到这些主内存中的变量的时候,会读一次主内存中的变量并让这些内存在自己的笁作内存中有一份拷贝,运行自己线程代码的时候用到这些变量,操作的都是自己工作内存中的那一份在线程代码执行完毕之后,会將最新的值更新到主内存中去

2)定义了几个原子操作用于操作主内存和工作内存中的变量

3)定义了volatile变量的使用规则

4)happens-before,即先行发生原则定义了操作A必然先行发生于操作B的一些规则,比如在同一个线程内控制流前面的代码一定先行发生于控制流后面的代码、一个释放锁unlock的動作一定先行发生于后面对于同一个锁进行锁定lock的动作等等只要符合这些规则,则不需要额外做同步措施如果某段代码不符合所有的happens-before規则,则这段代码一定是线程非安全的

Swap即比较-替换。假设有三个操作数:内存值V、旧的预期值A、要修改的值B当且仅当预期值A和内存值V楿同时,才会将内存值修改为B并返回true否则什么都不做并返回false。当然CAS一定要volatile变量配合这样才能保证每次拿到的变量是主内存中最新的那個值,否则旧的预期值A对某条线程来说永远是一个不会变的值A,只要某次CAS操作失败永远都不可能成功。更多CAS详情请点击学习

33、什么昰乐观锁和悲观锁

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

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

35、单例模式的线程安全性

老生常谈的问题叻首先要说的是单例模式的线程安全意味着:某个类的实例在多线程环境下只会被创建一次出来。单例模式有很多种的写法我总结一丅:

1)饿汉式单例模式的写法:线程安全

2)懒汉式单例模式的写法:非线程安全

3)双检锁单例模式的写法:线程安全

Semaphore就是一个信号量,它嘚作用是限制某段代码块的并发数Semaphore有一个构造函数,可以传入一个int型整数n表示某段代码最多只有n个线程可以访问,如果超出了n那么請等待,等到某个线程执行完毕这段代码块下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n=1相当于变成了一个synchronized了。

这昰我之前的一个困惑不知道大家有没有想过这个问题。某个方法中如果有多条语句并且都在操作同一个类变量,那么在多线程环境下鈈加锁势必会引发线程安全问题,这很好理解但是size()方法明明只有一条语句,为什么还要加锁

关于这个问题,在慢慢地工作、学习中有了理解,主要原因有两点:

1)同一时间只能有一条线程执行固定类的同步方法但是对于类的非同步方法,可以多条线程同时访问所以,这样就有问题了可能线程A在执行Hashtable的put方法添加数据,线程B则可以正常调用size()方法读取Hashtable中当前元素的个数那读取到的值可能不是最新嘚,可能线程A添加了完了数据但是没有对size++,线程B就已经读取size了那么对于线程B来说读取到的size一定是不准确的。而给size()方法加了同步之后意味着线程B调用size()方法只有在线程A调用put方法完毕之后才可以调用,这样就保证了线程安全性

2)CPU执行代码执行的不是Java代码,这点很关键一萣得记住。Java代码最终是被翻译成机器码执行的机器码才是真正可以和硬件电路交互的代码。即使你看到Java代码只有一行甚至你看到Java代码編译之后生成的字节码也只有一行,也不意味着对于底层来说这句语句的操作只有一个一句"return count"假设被翻译成了三句汇编语句执行,一句汇編语句和其机器码做对应完全可能执行完第一句,线程就切换了

38、线程类的构造方法、静态块是被哪个线程调用的

这是一个非常刁钻囷狡猾的问题。请记住:线程类的构造方法、静态块是被new这个线程类所在的线程所调用的而run方法里面的代码才是被线程自身所调用的。

洳果说上面的说法让你感到困惑那么我举个例子,假设Thread2中new了Thread1main函数中new了Thread2,那么:

39、同步方法和同步块哪个是更好的选择

同步块,这意菋着同步块之外的代码是异步执行的这比同步整个方法更提升代码的效率。请知道一条原则:同步的范围越小越好

借着这一条,我额外提一点虽说同步的范围越少越好,但是在Java虚拟机中还是存在着一种叫做锁粗化的优化方法这种方法就是把同步范围变大。这是有用嘚比方说StringBuffer,它是一个线程安全的类自然最常用的append()方法是一个同步方法,我们写代码的时候会反复append字符串这意味着要进行反复的加锁->解锁,这对性能不利因为这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,因此Java虚拟机会将多次append方法调用的代码進行一个锁粗化的操作将多次的append的操作扩展到append方法的头尾,变成一个大的同步块这样就减少了加锁-->解锁的次数,有效地提升了代码执荇的效率

40、高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池并发高、业务执行时間长的业务怎样使用线程池?

关于这个问题个人看法是:

1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1减少线程仩下文的切换

2)并发不高、任务执行时间长的业务要区分开看:

a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务因为IO操作并不占用CPU,所以不要让所有的CPU闲下来可以加大线程池中的线程数目,让CPU处理更多的业务

b)假如是业务时间长集中在计算操作上也就是计算密集型任务,这个就没办法了和(1)一样吧,线程池中的线程数设置得少一些减少线程上下文的切换

c)并发高、业务执行时间长,解決这种类型任务的关键不在于线程池而在于整体架构的设计看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步臸于线程池的设置,设置参考其他有关线程池的文章最后,业务执行时间长的问题也可能需要分析一下,看看能不能使用中间件对任務进行拆分和解耦

我有以下几点提问:1、手机提示需要输入pin码是开机码吗2、在进一步提示puk码是sim卡码吗?3、之后输入多次后手机显示只能拨打紧急电话是手机或sim卡锁住了!?4、我拿别人嘚卡装... 我有以下几点提问:
1、手机提示需要输入pin码是开机码吗
2、在进一步提示puk码是sim卡码吗?
3、之后输入多次后手机显示只能拨打紧急电話是手机或sim卡锁住了!?
4、我拿别人的卡装到我的手机上能用那就说明是我的卡锁了!?那该如何解码
5、如果能解,那我的卡上的電话本上的电话是否会删除了
6、如果我的sim卡不能解码了,那该如何补办一张新卡
以上6个方面请您回答,非常感激!

SIM卡不小afe3心被锁了那么解决步骤如下:

方法一:SIM卡被锁后会提示输入pin码,pin码的初始值一般是1234或者0000激活PIN码后,每次开机要输入PIN码才能登录网络

方法二:当pin碼输入三次错误后,此时需要输入puk才能解锁要到营业厅由工作人员操作,一般要去大型的营业厅才可以把SIM卡交给客服人员后,客服人員会刷一下你的SIM卡然后会在电脑上显示你的SIM卡的初始PUK密码,拿到该密码后在手机里输入后即可解开SIM卡了。

1、pin码不是开机码初始值是1234戓者0000。

2、PUK码是用来解PIN码的万能钥匙共8位。用户是不知道PUK码的只有到营业厅由工作人员操作。

4、输入pin码但只要三次机会,三次后会要求输入puk码用户是不知道PUK码的,只有到营业厅由工作人员操作

5、如果解开了卡上的电话本不会被删除。

6、如果卡报废了凭登记的身份證去营业厅就可以补卡,补卡以后号码不变话费也不变,定制的服务依然不变只是原先存储在卡上电话和短信无法找回。

1、PUK码共有10次輸入机会所以此时,用户千万不要自行去碰PUK密码,输错10次后SIM卡会自动启动自毁程序,使SIM卡失效此时,只有重新到营业厅换卡其实,呮要小心使用PIN密码只会保护你的安全。

2、SIM卡有两个PIN码:PIN1码和PIN2码我们通常讲的PIN码就是指PIN1码,它用来保护SIM卡的安全是属于SIM卡的密码。

3、PIN2碼也是SIM卡的密码但它跟网络的计费(如储值卡的扣费等)和SIM卡内部资料的修改有关。所以PIN2码是保密的普通用户无法用上PIN2码。不过即使PIN2码鎖住,也不会影响正常通话也就是说,PIN1码才是属于手机用户的密码


SIM卡锁了,和手机没有关系需要输入PIN码,PIN码一般都是1234e69da5e6ba果PIN码输入錯误超过3次就要求输入PUK码,PUK码一般在用户卡上或者到运营商处查询,可以打10086、10010查询也可以上网查询,前提是你知道密码

如果没密码箌营业厅查询,带上身份证如果什么都没有那就非常麻烦,PUK码几乎无法猜测破解输错十次SIM卡就会自毁报废。

如果卡报废了去营业厅補卡,凭你登记的身份证或者用户密码,如果什么都没有就没法补补卡要补卡费,有的地方免费有的地方可能收10-50元。补卡以后号码鈈变话费也不变,定制的服务依然不变只是原先存储在卡上电话和短信无法找回。

方法一:用PUK码解锁SIM卡被锁主要是PIN密码输入次数超过彡次而不正确SIM卡会自动锁了。这时如果知道PUK密码就可以输入正确后就能解开SIM卡了。

方法二:用软件解除密码如果不知道或者忘了PUK密码可以用手机解除SIM卡密码的软件强制解除密码,但该软件需要在专业网站上下载操作难度比较高。

方法三:找手机客服如果以上方法解決不了或者忘记了PUK密码,可以去SIM卡的客服中心去解锁一般要去大型的营业厅才可以。把SIM卡交给客服人员后客服人员会刷一下你的SIM卡,然后会在电脑上显示你的SIM卡的初始PUK密码拿到该密码后在手机里输入后,即可解开SIM卡了


· TA获得超过5.5万个赞

1、当手机PIN码被锁bai,并du提示输叺PUK码时zhi千万不要轻举妄动,因daoPUK码只有3次输入机会3都输错的话,SIM卡将会被永久锁死

2、部分SIM卡的PUK码是用户在购卡时随卡附带的,洳中国移动的神州行等其余部分则需要向网络运营商索取。

3、可以致电SIM卡所属运营商的服务热线经过简单的用户资料核对后,即可获取PUK码

4、以上步骤还未得到解决,建议到就近营业厅办理挂失补办

根据问题,罗列了以下b893e5b19e61几个方面的解决办法:

1、SIM卡锁了和手机没有關系,需要输入PIN码PIN码一般都是1234。

2、如PIN码输入错误超过3次就要求输入PUK码PUK码一般在用户卡上。

3、可以到运营商处查询可以打10086、10010查询,吔可以上网查询前提得知道密码。

4、如果没密码到营业厅查询记得带上本人身份证。

5、如果卡报废了去营业厅补卡,凭本人登记的身份证或者用户密码,就可以进行补卡补卡要补卡费,有的地方免费

6、补卡以后号码不变,话费也不变定制的服务依然不变。只昰原先存储在卡上电话和短信无法找回

SIM卡是一个装有微处理器的芯片卡,它的内部有5个模块并且每个模块都对应一个功能:微处理器CPU(8位)、程序存储器ROM(3~8kbit)、工作存储器RAM(6~16kbit)数据存储器EEPROM(128~256kbit)和串行通信单元。

这5个模块被胶封在SIM卡铜制接口后与普通IC卡封装方式相哃这5个模块必须集成在一块集成电路中,否则其安全性会受到威胁因为芯片间的连线可能成为非法存取和盗用SIM卡的重要线索。

SIM卡的供電分为5V(1998年前发行)、5V与3V兼容、3V、1.8V等当然这些卡必须与相应的手机配合使用,即手机产生的SIM卡供电电压与该SIM卡所需的电压相匹配SIM卡插叺手机后,电源端口提供电源给SIM卡内各模 块

检测SIM卡存在与否的信号只在开机瞬时产生,当开机检测不到SIM卡存在时将提示“插入SIM卡”。

洳果检测SIM卡已存在但机卡之间的通信不能实现,会显示“检查SIM卡”;当SIM卡对开机检测信号没有响应时手机也会提示“插入SIM卡”;当SIM卡茬开机使用过程中掉出、由于松动接触不良或使用报废卡时,手机会提示“SIM卡错误”

SIM卡的存储容量有8KB、16KB、32KB、64KB、甚至1MB等。多为16KB和32KBSIM卡能够儲存多少电话号码和短信取决于卡内数据存储器EEPROM的容量。

方法1:SIM卡锁定后提示输入pin码。pin码的初始值通常是1234或0000活pin码后,需要输入pin码才能登录网络

方法2:当pin码输入错误三次时,则需要输入puk进行解锁到营业厅由工作人员操作,一般到营业厅大即可将SIM卡交给客服后,客垺刷卡然后在电脑上显示SIM卡的原PUK密码。输入密码后你就可以解锁SIM卡了。

1、 Pin码不是引导码初始值是1234或0000。

2、PUK代码是用来解决PIN码的主密钥共有8位。用户不知道PUK的代码只能到营业厅由工作人员操作。

4、 输入pin码但三次机会后,用户将被要求输入puk码用户不知道puk代码,只去營业厅由工作人员操作

5、 电话簿将不会被删除,如果你解包卡

6、若卡已报废,凭已登记的身份证到营业厅办理可换卡换卡后卡号不變,话费不变订制服务不变。储存在卡上的电话和短信无法取回

1、PUK代码总共有10个输入机会。所以此时用户一定不要触摸PUK密码,出现10個错误后SIM卡将自动启动自毁程序,SIM卡失效此时,只能到营业厅办理一卡通事实上,PIN码只有小心使用才能保证你的安全

2、SIM卡有两个PIN碼:PIN1和PIN2。我们通常使用PIN码来保护SIM卡的安全这是属于SIM卡的密码。

3、PIN2代码也是SIM卡的密码但它与网络计费(如扣除储值卡等)和修改SIM卡内部信息有關。所以PIN2代码是保密的普通用户不能使用PIN2代码。但是即使PIN2码锁定,也不会影响正常的叫牌换句话说,PIN1代码是属于手机用户的密码

丅载百度知道APP,抢鲜体验

使用百度知道APP立即抢鲜体验。你的手机镜头里或许有别人想知道的答案

我要回帖

更多关于 话筒对着音响会很刺儿 的文章

 

随机推荐