北京网站建设公司,淄博营销型网站建设,php 网站 整合 数据库,怎么买wordpress主题✅作者简介#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者#xff0c;修心和技术同步精进。 #x1f34e;个人主页#xff1a;Java Fans的博客 #x1f34a;个人信条#xff1a;不迁怒#xff0c;不贰过。小知识#xff0c;大智慧。 #x1f49e;当前专栏… ✅作者简介2022年博客新星 第八。热爱国学的Java后端开发者修心和技术同步精进。 个人主页Java Fans的博客 个人信条不迁怒不贰过。小知识大智慧。 当前专栏Java面试题总结 ✨特色专栏国学周更-心性养成之路 本文内容Java面试——多线程并发篇 文章目录1、说说Java中实现多线程有几种方法2、如何停止一个正在运行的线程3、notify()和notifyAll()有什么区别4、sleep()和wait() 有什么区别5、volatile 是什么?可以保证有序性吗?6、Thread 类中的start() 和 run() 方法有什么区别7、为什么wait, notify 和 notifyAll这些方法不在thread类里8、为什么wait和notify方法要在同步块中调用9、Java中interrupted 和 isInterruptedd方法的区别10、Java中synchronized 和 ReentrantLock 有什么不同11、有三个线程T1,T2,T3,如何保证顺序执行12、SynchronizedMap和ConcurrentHashMap有什么区别13、什么是线程安全14、Thread类中的yield方法有什么作用15、Java线程池中submit() 和 execute()方法有什么区别16、说一说自己对于 synchronized 关键字的了解17、说说自己是怎么使用 synchronized 关键字18、什么是线程安全Vector是一个线程安全类吗19、 volatile关键字的作用20、常用的线程池有哪些21、简述一下你对线程池的理解22、Java程序是如何执行的23、锁的优化机制了解吗24、说说进程和线程的区别25产生死锁的四个必要条件26、如何避免死锁27线程池核心线程数怎么设置呢28Java线程池中队列常用类型有哪些29线程安全需要保证几个基本特征30说一下线程之间是如何通信的31、CAS的原理呢32、CAS有什么缺点吗33、引用类型有哪些有什么区别34、说说ThreadLocal原理35、线程池原理知道吗以及核心参数36、 线程池的拒绝策略有哪些37、说说你对JMM内存模型的理解为什么需要JMM38、多线程有什么用39、说说CyclicBarrier和CountDownLatch的区别40、什么是AQS41、了解Semaphore吗42、什么是Callable和Future?43、什么是阻塞队列阻塞队列的实现原理是什么如何使用阻44、什么是多线程中的上下文切换45、什么是Daemon线程它有什么意义46、乐观锁和悲观锁的理解及如何实现有哪些实现方式1、说说Java中实现多线程有几种方法
创建线程的常用三种方式
继承Thread类实现Runnable接口实现Callable接口 JDK1.5 线程池方式创建 通过继承Thread类或者实现Runnable接口、Callable接口都可以实现多线程不过实现Runnable 接口与实现Callable接口的方式基本相同只是Callable接口里定义的方法返回值可以声明抛出异 常而已。因此将实现Runnable接口和实现Callable接口归为一种方式。这种方式与继承Thread方式 之间的主要差别如下。 采用实现Runnable、Callable接口的方式创建线程的优缺点 优点线程类只是实现了Runnable或者Callable接口还可以继承其他类。这种方式下多个线程 可以共享一个target对象所以非常适合多个相同线程来处理同一份资源的情况从而可以将 CPU、代码和数据分开形成清晰的模型较好的体现了面向对象的思想。 缺点编程稍微复杂一些如果需要访问当前线程则必须使用 Thread.currentThread() 方法 采用继承Thread类的方式创建线程的优缺点 优点编写简单如果需要访问当前线程则无需使用 Thread.currentThread() 方法直接使用 this即可获取当前线程 缺点因为线程类已经继承了Thread类Java语言是单继承的所以就不能再继承其他父类了。
2、如何停止一个正在运行的线程
1、使用退出标志使线程正常退出也就是当run方法完成后线程终止。 2、使用stop方法强行终止但是不推荐这个方法因为stop和suspend及resume一样都是过期作 废的方法。 3、使用interrupt方法中断线程。 class MyThread extends Thread { volatile boolean stop false; public void run() { while (!stop) { System.out.println(getName() is running); try { sleep(1000); } catch (InterruptedException e) { System.out.println(“week up from blcok…”); stop true; // 在异常处理代码中修改共享变量的状态 } } System.out.println(getName() is exiting…); } } class InterruptThreadDemo3 { public static void main(String[] args) throws InterruptedException { MyThread m1 new MyThread(); System.out.println(“Starting thread…”); m1.start(); Thread.sleep(3000); System.out.println(Interrupt thread…: m1.getName()); m1.stop true; // 设置共享变量为true m1.interrupt(); // 阻塞时退出阻塞状态 Thread.sleep(3000); // 主线程休眠3秒以便观察线程m1的中断情况 System.out.println(“Stopping application…”); } }
3、notify()和notifyAll()有什么区别
notify可能会导致死锁而notifyAll则不会 任何时候只有一个线程可以获得锁也就是说只有一个线程可以运行synchronized 中的代码 使用notifyall,可以唤醒 所有处于wait状态的线程使其重新进入锁的争夺队列中而notify只能唤 醒一个。 wait() 应配合while循环使用不应使用if务必在wait()调用前后都检查条件如果不满足必须调 用notify()唤醒另外的线程来处理自己继续wait()直至条件满足再往下执行。 notify() 是对notifyAll()的一个优化但它有很精确的应用场景并且要求正确使用。不然可能导致 死锁。正确的场景应该是 WaitSet中等待的是相同的条件唤醒任一个都能正确处理接下来的事 项如果唤醒的线程无法正确处理务必确保继续notify()下一个线程并且自身需要重新回到 WaitSet中.
4、sleep()和wait() 有什么区别
对于sleep()方法我们首先要知道该方法是属于Thread类中的。而wait()方法则是属于Object类 中的。 sleep()方法导致了程序暂停执行指定的时间让出cpu该其他线程但是他的监控状态依然保持 者当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中线程不会释放对象 锁。 当调用wait()方法的时候线程会放弃对象锁进入等待此对象的等待锁定池只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
5、volatile 是什么?可以保证有序性吗?
一旦一个共享变量类的成员变量、类的静态成员变量被volatile修饰之后那么就具备了两层语 义 1保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值这新值对 其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。 2禁止进行指令重排序。 volatile 不是原子性操作 什么叫保证部分有序性? 当程序执行到volatile变量的读操作或者写操作时在其前面的操作的更改肯定全部已经进行且结 果已经对后面的操作可见在其后面的操作肯定还没有进行
x 2; //语句1 y 0; //语句2 flag true; //语句3 x 4; //语句4 y -1; //语句5 由于flag变量为volatile变量那么在进行指令重排序的过程的时候不会将语句3放到语句1、语句 2前面也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5 的顺序是不作任何保证的。 使用volatile 一般用于 状态标记量 和 单例模式的双检锁。
6、Thread 类中的start() 和 run() 方法有什么区别
start()方法被用来启动新创建的线程而且start()内部调用了run()方法这和直接调用run()方法的 效果不一样。当你调用run()方法的时候只会是在原来的线程中调用没有新的线程启动start() 方法才会启动新线程。
7、为什么wait, notify 和 notifyAll这些方法不在thread类里
面 明显的原因是JAVA提供的锁是对象级的而不是线程级的每个对象都有锁通过线程获得。如果线 程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中线 程正在等待的是哪个锁就不明显了。简单的说由于waitnotify和notifyAll都是锁级别的操作所 以把他们定义在Object类中因为锁属于对象。
8、为什么wait和notify方法要在同步块中调用
只有在调用线程拥有某个对象的独占锁时才能够调用该对象的wait(),notify()和notifyAll()方 法。如果你不这么做你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。 wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前当前线程必须已经 获得该对象的锁。因此线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方 法。 在调用对象的notify()和notifyAll()方法之前调用线程必须已经得到该对象的锁。因此必须在某 个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。 调用wait()方法的原因通常是调用线程希望某个特殊的状态(或变量)被设置之后再继续执行。调用 notify()或notifyAll()方法的原因通常是调用线程希望告诉其他等待中的线程:“特殊状态已经被设 置”。这个状态作为线程间通信的通道它必须是一个可变的共享状态(或变量)。
9、Java中interrupted 和 isInterruptedd方法的区别
interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中 断机制是用内部标识来实现的调用Thread.interrupt()来中断一个线程就会设置中断标识为true。 当中断线程调用静态方法Thread.interrupted()来检查中断状态时中断状态会被清零。而非静态方 法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出 InterruptedException异常的方法都会将中断状态清零。无论如何一个线程的中断状态有有可能 被其它线程调用中断来改变。
10、Java中synchronized 和 ReentrantLock 有什么不同
相似点 这两种同步方式有很多相似之处它们都是加锁方式同步而且都是阻塞式的同步也就是说当如 果一个线程获得了对象锁进入了同步块其他访问该同步块的线程都必须阻塞在同步块外面等 待而进行线程阻塞和唤醒的代价是比较高的. 区别 这两种方式最大区别就是对于Synchronized来说它是java语言的关键字是原生语法层面的互 斥需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁需要lock()和 unlock()方法配合try/finally语句块来完成。 Synchronized进过编译会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码 指令。在执行monitorenter指令时首先要尝试获取对象锁。如果这个对象没被锁定或者当前线 程已经拥有了那个对象锁把锁的计算器加1相应的在执行monitorexit指令时会将锁计算器就 减1当计算器为0时锁就被释放了。如果获取对象锁失败那当前线程就要阻塞直到对象锁被 另一个线程释放为止。 由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁相比Synchronized ReentrantLock类提供了一些高级功能主要有以下3项 1.等待可中断持有锁的线程长期不释放的时候正在等待的线程可以选择放弃等待这相当于 Synchronized来说可以避免出现死锁的情况。 2.公平锁多个线程等待同一个锁时必须按照申请锁的时间顺序获得锁Synchronized锁非公平 锁ReentrantLock默认的构造函数是创建的非公平锁可以通过参数true设为公平锁但公平锁 表现的性能不是很好。 3.锁绑定多个条件一个ReentrantLock对象可以同时绑定对个对象。
11、有三个线程T1,T2,T3,如何保证顺序执行
在多线程中有多种方法让线程按特定顺序执行你可以用线程类的join()方法在一个线程中启动另一 个线程另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调 用T2T2调用T1)这样T1就会先完成而T3最后完成。 实际上先启动三个线程中哪一个都行 因为在每个线程的run方法中用join方法限定了三个线程的 执行顺序。 public class JoinTest2 { // 1.现在有T1、T2、T3三个线程你怎样保证T2在T1执行完后执行T3在T2执行完后执行 public static void main(String[] args) { final Thread t1 new Thread(new Runnable() { Override public void run() { System.out.println(“t1”); } }); final Thread t2 new Thread(new Runnable() { Override public void run() { try { // 引用t1线程等待t1线程执行完 t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“t2”); } }); Thread t3 new Thread(new Runnable() { Override public void run() { try { // 引用t2线程等待t2线程执行完 t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“t3”); }
}); t3.start();//这里三个线程的启动顺序可以任意大家可以试下 t2.start(); t1.start(); } }
12、SynchronizedMap和ConcurrentHashMap有什么区别
SynchronizedMap()和Hashtable一样实现上在调用map所有方法时都对整个map进行同步。 而ConcurrentHashMap的实现却更加精细它对map中的所有桶加了锁。所以只要有一个线程 访问map其他线程就无法进入map而如果一个线程在访问ConcurrentHashMap某个桶时其 他线程仍然可以对map执行某些操作。 所以ConcurrentHashMap在性能以及安全性方面明显比Collections.synchronizedMap()更加 有优势。同时同步操作精确控制到桶这样即使在遍历map时如果其他线程试图对map进行 数据修改也不会抛出ConcurrentModificationException。
13、什么是线程安全
线程安全就是说多线程访问同一段代码不会产生不确定的结果。 又是一个理论的问题各式各样的答案有很多我给出一个个人认为解释地最好的如果你的代码 在多线程下执行和在单线程下执行永远都能获得一样的结果那么你的代码就是线程安全的。 这个问题有值得一提的地方就是线程安全也是有几个级别的 1不可变 像String、Integer、Long这些都是final类型的类任何一个线程都改变不了它们的值要改变除 非新创建一个因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用 2绝对线程安全 不管运行时环境如何调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代 价Java中标注自己是线程安全的类实际上绝大多数都不是线程安全的不过绝对线程安全的 类Java中也有比方说CopyOnWriteArrayList、CopyOnWriteArraySet 3相对线程安全 相对线程安全也就是我们通常意义上所说的线程安全像Vector这种add、remove方法都是原子 操作不会被打断但也仅限于此如果有个线程在遍历某个Vector、有个线程同时在add这个 Vector99%的情况下都会出现ConcurrentModificationException也就是fail-fast机制。 4线程非安全 这个就没什么好说的了ArrayList、LinkedList、HashMap等都是线程非安全的类
14、Thread类中的yield方法有什么作用
Yield方法可以暂停当前正在执行的线程对象让其它有相同优先级的线程执行。它是一个静态方法 而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU执行yield()的线程有可 能在进入到暂停状态后马上又被执行。
15、Java线程池中submit() 和 execute()方法有什么区别
两个方法都可以向线程池提交任务execute()方法的返回类型是void它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象它定义在ExecutorService接口中它扩展了 Executor接口其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些 方法。
16、说一说自己对于 synchronized 关键字的了解
synchronized关键字解决的是多个线程之间访问资源的同步性synchronized关键字可以保证被它 修饰的方法或者代码块在任意时刻只能有一个线程执行。 另外在 Java 早期版本中 synchronized属于重量级锁效率低下因为监视器锁monitor是依赖于底层的操作系统的 Mutex Lock 来实现的Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一 个线程都需要操作系统帮忙完成而操作系统实现线程之间的切换时需要从用户态转换到内核 态这个状态之间的转换需要相对比较长的时间时间成本相对较高这也是为什么早期的 synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较 大优化所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优 化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。
17、说说自己是怎么使用 synchronized 关键字
修饰实例方法: 作用于当前对象实例加锁进入同步代码前要获得当前对象实例的锁 修饰静态方法: 也就是给当前类加锁会作用于类的所有对象实例因为静态成员不属于任何一个实例对象是类 成员 static 表明这是该类的一个静态资源不管new了多少个对象只有一份。所以如果一个 线程A调用一个实例对象的非静态 synchronized 方法而线程B需要调用这个实例对象所属类的静 态 synchronized 方法是允许的不会发生互斥现象因为访问静态 synchronized 方法占用的 锁是当前类的锁而访问非静态 synchronized 方法占用的锁是当前实例对象锁。 修饰代码块: 指 定加锁对象对给定对象加锁进入同步代码库前要获得给定对象的锁。 总结 synchronized 关 键字加到 static 静态方法和 synchronized(class)代码块上都是是给 Class 类上锁。synchronized 关键字加到实例方法上是给对象实例上锁。尽量不要使用 synchronized(String a) 因为JVM中字 符串常量池具有缓存功能
18、什么是线程安全Vector是一个线程安全类吗
如果你的代码所在的进程中有多个线程在同时运行而这些线程可能会同时运行这段代码。如果每 次运行结果和单线程运行的结果是一样的而且其他的变量 的值也和预期的是一样的就是线程安 全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失 误。很显然你可以将集合类分 成两组线程安全和非线程安全的。Vector 是用同步方法来实现线程 安全的, 而和它相似的ArrayList不是线程安全的。
19、 volatile关键字的作用
一旦一个共享变量类的成员变量、类的静态成员变量被volatile修饰之后那么就具备了两层语 义 保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值这新值对 其他线程来说是立即可见的。 禁止进行指令重排序。 volatile本质是在告诉jvm当前变量在寄存器工作内存中的值是不确定的需要从主存中读 取synchronized则是锁定当前变量只有当前线程可以访问该变量其他线程被阻塞住。 volatile仅能使用在变量级别synchronized则可以使用在变量、方法、和类级别的。 volatile仅能实现变量的修改可见性并不能保证原子性synchronized则可以保证变量的修改 可见性和原子性。 volatile不会造成线程的阻塞synchronized可能会造成线程的阻塞。 volatile标记的变量不会被编译器优化synchronized标记的变量可以被编译器优化。
20、常用的线程池有哪些
newSingleThreadExecutor创建一个单线程的线程池此线程池保证所有任务的执行顺序按 照任务的提交顺序执行。 newFixedThreadPool创建固定大小的线程池每次提交一个任务就创建一个线程直到线 程达到线程池的最大大小。 newCachedThreadPool创建一个可缓存的线程池此线程池不会对线程池大小做限制线 程池大小完全依赖于操作系统或者说JVM能够创建的最大线程大小。 newScheduledThreadPool创建一个大小无限的线程池此线程池支持定时以及周期性执行 任务的需求。 newSingleThreadExecutor创建一个单线程的线程池。此线程池支持定时以及周期性执行任 务的需求。
21、简述一下你对线程池的理解
如果问到了这样的问题可以展开的说一下线程池如何用、线程池的好处、线程池的启动策略 合理利用线程池能够带来三个好处。 第一降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二提高响应速度。当任务到达时任务可以不需要等到线程创建就能立即执行。 第三提高线程的可管理性。线程是稀缺资源如果无限制的创建不仅会消耗系统资源还会降 低系统的稳定性使用线程池可以进行统一的分配调优和监控。
22、Java程序是如何执行的
我们日常的工作中都使用开发工具IntelliJ IDEA 或 Eclipse 等可以很方便的调试程序或者是通 过打包工具把项目打包成 jar 包或者 war 包放入 Tomcat 等 Web 容器中就可以正常运行了但你 有没有想过 Java 程序内部是如何执行的其实不论是在开发工具中运行还是在 Tomcat 中运行 Java 程序的执行流程基本都是相同的它的执行流程如下 先把 Java 代码编译成字节码也就是把 .java 类型的文件编译成 .class 类型的文件。这个过程 的大致执行流程Java 源代码 - 词法分析器 - 语法分析器 - 语义分析器 - 字符码生成器 - 最终生成字节码其中任何一个节点执行失败就会造成编译失败 把 class 文件放置到 Java 虚拟机这个虚拟机通常指的是 Oracle 官方自带的 Hotspot JVM Java 虚拟机使用类加载器Class Loader装载 class 文件 类加载完成之后会进行字节码效验字节码效验通过之后 JVM 解释器会把字节码翻译成机器 码交由操作系统执行。但不是所有代码都是解释执行的JVM 对此做了优化比如以 Hotspot 虚拟机来说它本身提供了 JITJust In Time也就是我们通常所说的动态编译器 它能够在运行时将热点代码编译为机器码这个时候字节码就变成了编译执行。Java 程序执行 流程图如下
23、锁的优化机制了解吗
从JDK1.6版本之后synchronized本身也在不断优化锁的机制有些情况下他并不会是一个很重量 级的锁了。优化机制包括自适应锁、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁。 锁的状态从低到高依次为无锁-偏向锁-轻量级锁-重量级锁升级的过程就是从低到高降级在 一定条件也是有可能发生的。 自旋锁由于大部分时候锁被占用的时间很短共享变量的锁定时间也很短所有没有必要挂起 线程用户态和内核态的来回上下文切换严重影响性能。自旋的概念就是让线程执行一个忙循环 可以理解为就是啥也不干防止从用户态转入内核态自旋锁可以通过设置-XX:UseSpining来开 启自旋的默认次数是10次可以使用-XX:PreBlockSpin设置。 自适应锁自适应锁就是自适应的自旋锁自旋的时间不是固定时间而是由前一次在同一个锁上 的自旋时间和锁的持有者状态来决定。 锁消除锁消除指的是JVM检测到一些同步的代码块完全不存在数据竞争的场景也就是不需要 加锁就会进行锁消除。 锁粗化锁粗化指的是有很多操作都是对同一个对象进行加锁就会把锁的同步范围扩展到整个操 作序列之外。
偏向锁当线程访问同步块获取锁时会在对象头和栈帧中的锁记录里存储偏向锁的线程ID之后 这个线程再次进入同步块时都不需要CAS来加锁和解锁了偏向锁会永远偏向第一个获得锁的线 程如果后续没有其他线程获得过这个锁持有锁的线程就永远不需要进行同步反之当有其他 线程竞争偏向锁时持有偏向锁的线程就会释放偏向锁。可以用过设置-XX:UseBiasedLocking开 启偏向锁。 轻量级锁JVM的对象的对象头中包含有一些锁的标志位代码进入同步块的时候JVM将会使用 CAS方式来尝试获取锁如果更新成功则会把对象头中的状态位标记为轻量级锁如果更新失败 当前线程就尝试自旋来获得锁。 整个锁升级的过程非常复杂我尽力去除一些无用的环节简单来描述整个升级的机制。 简单点说偏向锁就是通过对象头的偏向线程ID来对比甚至都不需要CAS了而轻量级锁主要就 是通过CAS修改对象头锁记录和自旋来实现重量级锁则是除了拥有锁的线程其他全部阻塞。
24、说说进程和线程的区别
进程是一个“执行中的程序”是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体一个进程中拥有多个线程线程之间共享地址空间和其它资源所以 通信和同步等操作线程比进程更加容易线程上下文的切换比进程上下文切换要快很多。 1进程切换时涉及到当前进程的CPU环境的保存和新被调度运行进程的CPU环境的设置。 2线程切换仅需要保存和设置少量的寄存器内容不涉及存储管理方面的操作。
25产生死锁的四个必要条件
互斥条件一个资源每次只能被一个线程使用请求与保持条件一个线程因请求资源而阻塞时对已获得的资源保持不放不剥夺条件进程已经获得的资源在未使用完之前不能强行剥夺循环等待条件若干线程之间形成一种头尾相接的循环等待资源关系
26、如何避免死锁
指定获取锁的顺序举例如下
比如某个线程只有获得A锁和B锁才能对某资源进行操作在多线程条件下如何避免死锁获得锁的顺序是一定的比如规定只有获得A锁的线程才有资格获取B锁按顺序获取锁就可 以避免死锁
27线程池核心线程数怎么设置呢
分为CPU密集型和IO密集型 CPU 这种任务消耗的主要是 CPU 资源可以将线程数设置为 NCPU 核心数1比 CPU 核心数多出 来的一个线程是为了防止线程偶发的缺页中断或者其它原因导致的任务暂停而带来的影响。一旦 任务暂停CPU 就会处于空闲状态而在这种情况下多出来的一个线程就可以充分利用 CPU 的空 闲时间。 IO密集型 这种任务应用起来系统会用大部分的时间来处理 I/O 交互而线程在处理 I/O 的时间段内不会占 用 CPU 来处理这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中我们 可以多配置一些线程具体的计算方法是 核心线程数CPU核心数量*2。
28Java线程池中队列常用类型有哪些
ArrayBlockingQueue 是一个基于数组结构的有界阻塞队列此队列按 FIFO先进先出原则 对元素进行排序。 LinkedBlockingQueue 一个基于链表结构的阻塞队列此队列按FIFO 先进先出 排序元 素吞吐量通常要高于 ArrayBlockingQueue 。 SynchronousQueue 一个不存储元素的阻塞队列。 PriorityBlockingQueue 一个具有优先级的无限阻塞队列。 PriorityBlockingQueue 也是基于 最小二叉堆实现 DelayQueue
只有当其指定的延迟时间到了才能够从队列中获取到该元素。 DelayQueue 是一个没有大小限制的队列 因此往队列中插入数据的操作生产者永远不会被阻塞而只有获取数据的操作消费 者才会被阻塞。 这里能说出前三种也就差不多了如果能说全那是最好。
29线程安全需要保证几个基本特征
原子性简单说就是相关操作不会中途被其他线程干扰一般通过同步机制实现。 可见性是一个线程修改了某个共享变量其状态能够立即被其他线程知晓通常被解释为将 线程本地状态反映到主内存上volatile 就是负责保证可见性的。 有序性是保证线程内串行语义避免指令重排等。
30说一下线程之间是如何通信的
线程之间的通信有两种方式共享内存和消息传递。 共享内存 在共享内存的并发模型里线程之间共享程序的公共状态线程之间通过写-读内存中的公共状态来 隐式进行通信。典型的共享内存通信方式就是通过共享对象进行通信。 例如上图线程 A 与 线程 B 之间如果要通信的话那么就必须经历下面两个步骤
线程 A 把本地内存 A 更新过得共享变量刷新到主内存中去。线程 B 到主内存中去读取线程 A 之前更新过的共享变量。 消息传递 在消息传递的并发模型里线程之间没有公共状态线程之间必须通过明确的发送消息来显式进行 通信。在 Java 中典型的消息传递方式就是 wait() 和 notify() 或者 BlockingQueue 。
31、CAS的原理呢
CAS叫做CompareAndSwap比较并交换主要是通过处理器的指令来保证操作的原子性它包含 三个操作数
变量内存地址V表示旧的预期值A表示准备设置的新值B表示 当执行CAS指令时只有当V等于A时才会用B去更新V的值否则就不会执行更新操作。
32、CAS有什么缺点吗
CAS的缺点主要有3点 ABA问题ABA的问题指的是在CAS更新的过程中当读取到的值是A然后准备赋值的时候仍然是 A但是实际上有可能A的值被改成了B然后又被改回了A这个CAS更新的漏洞就叫做ABA。只是 ABA的问题大部分场景下都不影响并发的最终效果。 Java中有AtomicStampedReference来解决这个问题他加入了预期标志和更新后标志两个字段 更新时不光检查值还要检查当前的标志是否等于预期标志全部相等的话才会更新。 循环时间长开销大自旋CAS的方式如果长时间不成功会给CPU带来很大的开销。 只能保证一个共享变量的原子操作只对一个共享变量操作可以保证原子性但是多个则不行多 个可以通过AtomicReference来处理或者使用锁synchronized实现。
33、引用类型有哪些有什么区别
引用类型主要分为强软弱虚四种
强引用指的就是代码中普遍存在的赋值方式比如A a new A()这种。强引用关联的对象永 远不会被GC回收。软引用可以用SoftReference来描述指的是那些有用但是不是必须要的对象。系统在发生内存 溢出前会对这类引用的对象进行回收。弱引用可以用WeakReference来描述他的强度比软引用更低一点弱引用的对象下一次GC 的时候一定会被回收而不管内存是否足够。虚引用也被称作幻影引用是最弱的引用关系可以用PhantomReference来描述他必须和 ReferenceQueue一起使用同样的当发生GC的时候虚引用也会被回收。可以用虚引用来管 理堆外内存。
34、说说ThreadLocal原理
hreadLocal可以理解为线程本地变量他会在每个线程都创建一个副本那么在线程之间访问内部 副本变量就行了做到了线程之间互相隔离相比于synchronized的做法是用空间来换时间。 ThreadLocal有一个静态内部类ThreadLocalMapThreadLocalMap又包含了一个Entry数组 Entry本身是一个弱引用他的key是指向ThreadLocal的弱引用Entry具备了保存key value键值对 的能力。 弱引用的目的是为了防止内存泄露如果是强引用那么ThreadLocal对象除非线程结束否则始终无 法被回收弱引用则会在下一次GC的时候被回收。 但是这样还是会存在内存泄露的问题假如key和ThreadLocal对象被回收之后entry中就存在key 为null但是value有值的entry对象但是永远没办法被访问到同样除非线程结束运行。 但是只要ThreadLocal使用恰当在使用完之后调用remove方法删除Entry对象实际上是不会出 现这个问题的。
35、线程池原理知道吗以及核心参数
首先线程池有几个核心的参数概念
最大线程数maximumPoolSize核心线程数corePoolSize活跃时间keepAliveTime阻塞队列workQueue拒绝策略RejectedExecutionHandler 当提交一个新任务到线程池时具体的执行流程如下当我们提交任务线程池会根据corePoolSize大小创建若干任务数量线程执行任务当任务的数量超过corePoolSize数量后续的任务将会进入阻塞队列阻塞排队当阻塞队列也满了之后那么将会继续创建(maximumPoolSize-corePoolSize)个数量的线程来 执行任务如果任务处理完成maximumPoolSize-corePoolSize额外创建的线程等待 keepAliveTime之后被自动销毁如果达到maximumPoolSize阻塞队列还是满的状态那么将根据不同的拒绝策略对应处理
36、 线程池的拒绝策略有哪些
主要有4种拒绝策略
AbortPolicy直接丢弃任务抛出异常这是默认策略CallerRunsPolicy只用调用者所在的线程来处理任务DiscardOldestPolicy丢弃等待队列中最旧的任务并执行当前任务DiscardPolicy直接丢弃任务也不抛出异常
37、说说你对JMM内存模型的理解为什么需要JMM
随着CPU和内存的发展速度差异的问题导致CPU的速度远快于内存所以现在的CPU加入了高速 缓存高速缓存一般可以分为L1、L2、L3三级缓存。基于上面的例子我们知道了这导致了缓存一致 性的问题所以加入了缓存一致性协议同时导致了内存可见性的问题而编译器和CPU的重排序 导致了原子性和有序性的问题JMM内存模型正是对多线程操作下的一系列规范约束因为不可能 让陈雇员的代码去兼容所有的CPU通过JMM我们才屏蔽了不同硬件和操作系统内存的访问差异 这样保证了Java程序在不同的平台下达到一致的内存访问效果同时也是保证在高效并发的时候程 序能够正确执行。 原子性Java内存模型通过read、load、assign、use、store、write来保证原子性操作此外还有 lock和unlock直接对应着synchronized关键字的monitorenter和monitorexit字节码指令。
可见性可见性的问题在上面的回答已经说过Java保证可见性可以认为通过volatile、 synchronized、final来实现。 有序性由于处理器和编译器的重排序导致的有序性问题Java通过volatile、synchronized来保 证。 happen-before规则 虽然指令重排提高了并发的性能但是Java虚拟机会对指令重排做出一些规则限制并不能让所有 的指令都随意的改变执行位置主要有以下几点
单线程每个操作happen-before于该线程中任意后续操作volatile写happen-before与后续对这个变量的读synchronized解锁happen-before后续对这个锁的加锁final变量的写happen-before于final域对象的读happen-before后续对final变量的读传递性规则A先于BB先于C那么A一定先于C发生 说了半天到底工作内存和主内存是什么 主内存可以认为就是物理内存Java内存模型中实际就是虚拟机内存的一部分。而工作内存就是 CPU缓存他有可能是寄存器也有可能是L1\L2\L3缓存都是有可能的。
38、多线程有什么用
一个可能在很多人看来很扯淡的一个问题我会用多线程就好了还管它有什么用在我看来这 个回答更扯淡。所谓知其然知其所以然“会用只是知其然”“为什么用才是知其所以然”只 有达到知其然知其所以然的程度才可以说是把一个知识点运用自如。OK下面说说我对这个问题 的看法 1发挥多核CPU的优势 随着工业的进步现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的4核、8核甚至 16核的也都不少见如果是单线程的程序那么在双核CPU上就浪费了50%在4核CPU上就浪费 了75%。单核CPU上所谓的多线程那是假的多线程同一时间处理器只会处理一段逻辑只不过 线程之间切换得比较快看着像多个线程同时运行罢了。多核CPU上的多线程才是真正的多线 程它能让你的多段逻辑同时工作多线程可以真正发挥出多核CPU的优势来达到充分利用 CPU的目的。 2防止阻塞 从程序运行效率的角度来看单核CPU不但不会发挥出多线程的优势反而会因为在单核CPU上运 行多线程导致线程上下文的切换而降低程序整体的效率。但是单核CPU我们还是要应用多线程 就是为了防止阻塞。试想如果单核CPU使用单线程那么只要这个线程阻塞了比方说远程读取 某个数据吧对端迟迟未返回又没有设置超时时间那么你的整个程序在数据返回回来之前就停止
运行了。多线程可以防止这个问题多条线程同时运行哪怕一条线程的代码执行读取数据阻塞 也不会影响其它任务的执行。 3便于建模 这是另外一个没有这么明显的优点了。假设有一个大的任务A单线程编程那么就要考虑很多 建立整个程序模型比较麻烦。但是如果把这个大的任务A分解成几个小任务任务B、任务C、任务 D分别建立程序模型并通过多线程分别运行这几个任务那就简单很多了。
39、说说CyclicBarrier和CountDownLatch的区别
两个看上去有点像的类都在java.util.concurrent下都可以用来表示代码运行到某个点上二者 的区别在于 1CyclicBarrier的某个线程运行到某个点上之后该线程即停止运行直到所有的线程都到达了 这个点所有线程才重新运行CountDownLatch则不是某线程运行到某个点上之后只是给某 个数值-1而已该线程继续运行 2CyclicBarrier只能唤起一个任务CountDownLatch可以唤起多个任务 3CyclicBarrier可重用CountDownLatch不可重用计数值为0该CountDownLatch就不可再 用了
40、什么是AQS
简单说一下AQSAQS全称为AbstractQueuedSychronizer翻译过来应该是抽象队列同步器。 如果说java.util.concurrent的基础是CAS的话那么AQS就是整个Java并发包的核心了 ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS实际上以双向队列的形式 连接所有的Entry比方说ReentrantLock所有等待的线程都被放在一个Entry中并连成双向队 列前面一个线程使用ReentrantLock好了则双向队列实际上的第一个Entry开始运行。 AQS定义了对双向队列所有的操作而只开放了tryLock和tryRelease方法给开发者使用开发者可 以根据自己的实现重写tryLock和tryRelease方法以实现自己的并发功能。
41、了解Semaphore吗
emaphore就是一个信号量它的作用是限制某段代码块的并发数。Semaphore有一个构造函数 可以传入一个int型整数n表示某段代码最多只有n个线程可以访问如果超出了n那么请等待 等到某个线程执行完毕这段代码块下一个线程再进入。由此可以看出如果Semaphore构造函数中 传入的int型整数n1相当于变成了一个synchronized了。
42、什么是Callable和Future?
Callable接口类似于Runnable从名字就可以看出来了但是Runnable不会返回结果并且无法抛 出返回结果的异常而Callable功能更强大一些被线程执行后可以返回值这个返回值可以被 Future拿到也就是说Future可以拿到异步执行任务的返回值。可以认为是带有回调的 Runnable。 Future接口表示异步任务是还没有完成的任务给出的未来结果。所以说Callable用于产生结果 Future用于获取结果。
43、什么是阻塞队列阻塞队列的实现原理是什么如何使用阻
塞队列来实现生产者-消费者模型 阻塞队列BlockingQueue是一个支持两个附加操作的队列。 这两个附加的操作是在队列为空时获取元素的线程会等待队列变为非空。当队列满时存储元 素的线程会等待队列可用。 阻塞队列常用于生产者和消费者的场景生产者是往队列里添加元素的线程消费者是从队列里拿 元素的线程。阻塞队列就是生产者存放元素的容器而消费者也只从容器里拿元素。 JDK7提供了7个阻塞队列。分别是 ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列。 LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列。 PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列。 DelayQueue一个使用优先级队列实现的无界阻塞队列。 SynchronousQueue一个不存储元素的阻塞队列。 LinkedTransferQueue一个由链表结构组成的无界阻塞队列。 LinkedBlockingDeque一个由链表结构组成的双向阻塞队列。 Java 5之前实现同步存取时可以使用普通的一个集合然后在使用线程的协作和线程同步可以实 现生产者消费者模式主要的技术就是用好wait ,notify,notifyAll,sychronized这些关键字。而 在java 5之后可以使用阻塞队列来实现此方式大大简少了代码量使得多线程编程更加容易 安全方面也有保障。 BlockingQueue接口是Queue的子接口它的主要用途并不是作为容器而是作为线程同步的的工 具因此他具有一个很明显的特性当生产者线程试图向BlockingQueue放入元素时如果队列已 满则线程被阻塞当消费者线程试图从中取出一个元素时如果队列为空则该线程会被阻塞 正是因为它所具有这个特性所以在程序中多个线程交替向BlockingQueue中放入元素取出元 素它可以很好的控制线程之间的通信。 阻塞队列使用最经典的场景就是socket客户端数据的读取和解析读取数据的线程不断将数据放入 队列然后解析线程不断从队列取数据解析。
44、什么是多线程中的上下文切换
在上下文切换过程中CPU会停止处理当前运行的程序并保存当前程序运行的具体位置以便之后 继续运行。从这个角度来看上下文切换有点像我们同时阅读几本书在来回切换书本的同时我们 需要记住每本书当前读到的页码。 在程序中上下文切换过程中的“页码”信息是保存在进程控制块PCB中的。PCB还经常被称 作“切换桢”switchframe。“页码”信息会一直保存到CPU的内存中直到他们被再次使用。 上下文切换是存储和恢复CPU状态的过程它使得线程执行能够从中断点恢复执行。上下文切换是 多任务操作系统和多线程环境的基本特征。
45、什么是Daemon线程它有什么意义
所谓后台(daemon)线程也叫守护线程是指在程序运行的时候在后台提供一种通用服务的线程 并且这个线程并不属于程序中不可或缺的部分。 因此当所有的非后台线程结束时程序也就终止了同时会杀死进程中的所有后台线程。反过来 说 只要有任何非后台线程还在运行程序就不会终止。 必须在线程启动之前调用setDaemon()方法才能把它设置为后台线程。注意后台进程在不执行 finally子句的情况下就会终止其run()方法。 比如JVM的垃圾回收线程就是Daemon线程Finalizer也是守护线程。
46、乐观锁和悲观锁的理解及如何实现有哪些实现方式
悲观锁总是假设最坏的情况每次去拿数据的时候都认为别人会修改所以每次在拿数据的时候 都会上锁这样别人想拿这个数据就会阻塞直到它拿到锁。 传统的关系型数据库里边就用到了很多这种锁机制比如行锁表锁等读锁写锁等都是在做 操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。 乐观锁顾名思义就是很乐观每次去拿数据的时候都认为别人不会修改所以不会上锁但是 在更新的时候会判断一下在此期间别人有没有去更新这个数据可以使用版本号等机制。 乐观锁适用于多读的应用类型这样可以提高吞吐量像数据库提供的类似于write_condition机 制其实都是提供的乐观锁。 在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实 现的。 乐观锁的实现方式 1、使用版本标识来确定读到的数据与提交时的数据是否一致。提交后修改版本标识不一致时可 以采取丢弃和再次尝试的策略。
2、java中的Compare and Swap即CAS 当多个线程尝试使用CAS同时更新同一个变量时只有其 中一个线程能更新变量的值而其它线程都失败失败的线程并不会被挂起而是被告知这次竞争 中失败并可以再次尝试。 CAS 操作中包含三个操作数 —— 需要读写的内存位置V、进行比 较的预期原值A和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配那么处理器会自 动将该位置值更新为新值B。否则处理器不做任何操作。 CAS缺点
ABA问题比如说一个线程one从内存位置V中取出A这时候另一个线程two也从内存中取出 A并且two进行了一些操作变成了B然后two又将V位置的数据变成A这时候线程one进行 CAS操作发现内存中仍然是A然后one操作成功。尽管线程one的CAS操作成功但可能存在 潜藏的问题。从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决 ABA问题。循环时间长开销大对于资源竞争严重线程冲突严重的情况CAS自旋的概率会比较大 从而浪费更多的CPU资源效率低于synchronized。只能保证一个共享变量的原子操作当对一个共享变量执行操作时我们可以使用循环CAS的 方式来保证原子操作但是对多个共享变量操作时循环CAS就无法保证操作的原子性这个 时候就可以用锁。 码文不易本篇文章就介绍到这里如果想要学习更多Java系列知识点击关注博主博主带你零基础学习Java知识。与此同时对于日常生活有困扰的朋友欢迎阅读我的第四栏目《国学周更—心性养成之路》学习技术的同时我们也注重了心性的养成。
文章转载自: http://www.morning.wlxfj.cn.gov.cn.wlxfj.cn http://www.morning.pwlxy.cn.gov.cn.pwlxy.cn http://www.morning.lwzpp.cn.gov.cn.lwzpp.cn http://www.morning.hphrz.cn.gov.cn.hphrz.cn http://www.morning.qxljc.cn.gov.cn.qxljc.cn http://www.morning.shyqcgw.cn.gov.cn.shyqcgw.cn http://www.morning.txfxy.cn.gov.cn.txfxy.cn http://www.morning.kcypc.cn.gov.cn.kcypc.cn http://www.morning.nhzps.cn.gov.cn.nhzps.cn http://www.morning.rnxs.cn.gov.cn.rnxs.cn http://www.morning.dighk.com.gov.cn.dighk.com http://www.morning.nbhft.cn.gov.cn.nbhft.cn http://www.morning.jxcwn.cn.gov.cn.jxcwn.cn http://www.morning.ldynr.cn.gov.cn.ldynr.cn http://www.morning.vvdifactory.com.gov.cn.vvdifactory.com http://www.morning.wqbzt.cn.gov.cn.wqbzt.cn http://www.morning.hsrpc.cn.gov.cn.hsrpc.cn http://www.morning.chmcq.cn.gov.cn.chmcq.cn http://www.morning.ptzf.cn.gov.cn.ptzf.cn http://www.morning.xbyyd.cn.gov.cn.xbyyd.cn http://www.morning.wqbfd.cn.gov.cn.wqbfd.cn http://www.morning.rpjyl.cn.gov.cn.rpjyl.cn http://www.morning.qpsft.cn.gov.cn.qpsft.cn http://www.morning.qgxnw.cn.gov.cn.qgxnw.cn http://www.morning.nchsz.cn.gov.cn.nchsz.cn http://www.morning.lxlfr.cn.gov.cn.lxlfr.cn http://www.morning.nzmhk.cn.gov.cn.nzmhk.cn http://www.morning.bjjrtcsl.com.gov.cn.bjjrtcsl.com http://www.morning.fhqdb.cn.gov.cn.fhqdb.cn http://www.morning.dblgm.cn.gov.cn.dblgm.cn http://www.morning.jxrpn.cn.gov.cn.jxrpn.cn http://www.morning.gqhgl.cn.gov.cn.gqhgl.cn http://www.morning.wdshp.cn.gov.cn.wdshp.cn http://www.morning.ngpdk.cn.gov.cn.ngpdk.cn http://www.morning.nqlkb.cn.gov.cn.nqlkb.cn http://www.morning.lfxcj.cn.gov.cn.lfxcj.cn http://www.morning.yqfdl.cn.gov.cn.yqfdl.cn http://www.morning.nmfwm.cn.gov.cn.nmfwm.cn http://www.morning.ltqzq.cn.gov.cn.ltqzq.cn http://www.morning.lxqyf.cn.gov.cn.lxqyf.cn http://www.morning.qbzfp.cn.gov.cn.qbzfp.cn http://www.morning.ylxgw.cn.gov.cn.ylxgw.cn http://www.morning.fhsgw.cn.gov.cn.fhsgw.cn http://www.morning.zxhhy.cn.gov.cn.zxhhy.cn http://www.morning.hcgbm.cn.gov.cn.hcgbm.cn http://www.morning.skfkx.cn.gov.cn.skfkx.cn http://www.morning.qbtkg.cn.gov.cn.qbtkg.cn http://www.morning.tmzlt.cn.gov.cn.tmzlt.cn http://www.morning.ywxln.cn.gov.cn.ywxln.cn http://www.morning.wanjia-sd.com.gov.cn.wanjia-sd.com http://www.morning.wcqkp.cn.gov.cn.wcqkp.cn http://www.morning.rwxnn.cn.gov.cn.rwxnn.cn http://www.morning.drcnf.cn.gov.cn.drcnf.cn http://www.morning.mgbsp.cn.gov.cn.mgbsp.cn http://www.morning.tktcr.cn.gov.cn.tktcr.cn http://www.morning.yqpzl.cn.gov.cn.yqpzl.cn http://www.morning.rbgqn.cn.gov.cn.rbgqn.cn http://www.morning.jljiangyan.com.gov.cn.jljiangyan.com http://www.morning.zzhqs.cn.gov.cn.zzhqs.cn http://www.morning.fglth.cn.gov.cn.fglth.cn http://www.morning.zntf.cn.gov.cn.zntf.cn http://www.morning.gmjkn.cn.gov.cn.gmjkn.cn http://www.morning.pzcqz.cn.gov.cn.pzcqz.cn http://www.morning.wdwfm.cn.gov.cn.wdwfm.cn http://www.morning.gtqx.cn.gov.cn.gtqx.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.stxg.cn.gov.cn.stxg.cn http://www.morning.cokcb.cn.gov.cn.cokcb.cn http://www.morning.qsmch.cn.gov.cn.qsmch.cn http://www.morning.kghhl.cn.gov.cn.kghhl.cn http://www.morning.qxltp.cn.gov.cn.qxltp.cn http://www.morning.nrxsl.cn.gov.cn.nrxsl.cn http://www.morning.wnhgb.cn.gov.cn.wnhgb.cn http://www.morning.dansj.com.gov.cn.dansj.com http://www.morning.ctfh.cn.gov.cn.ctfh.cn http://www.morning.sskhm.cn.gov.cn.sskhm.cn http://www.morning.npxht.cn.gov.cn.npxht.cn http://www.morning.pndhh.cn.gov.cn.pndhh.cn http://www.morning.mqpdl.cn.gov.cn.mqpdl.cn http://www.morning.bnfjh.cn.gov.cn.bnfjh.cn