尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

多线程面试题

多线程面试题 多线程相关概念概念多线程是指程序中包含多个执行流即在一个程序中可以同时运行多个不同的线程来执行不同的任务。线程安全指多个线程在执行同一段代码的时候采用加锁机制使每次的执行结果和单线程执行的结果都是一样的不存在执行结果的二义性。线程不安全就是不提供加锁机制保护有可能出现多个线程先后更改数据造成所得到的数据是脏数据注意只有在多线程环境下才会考虑线程安全问题知识延申Java 实现线程安全的三种方式及如何保证线程安全为什么要使用并发编程充分利用多核CPU的计算能力通过并发编程的形式可以将多核CPU的计算能力发挥到极致性能得到提升方便进行业务拆分提升系统并发能力和性能在特殊的业务场景下先天的就适合于并发编程。现在的系统动不动就要求百万级甚至千万级的并发量而多线程并发编程正是开发高并发系统的基础利用好多线程机制可以大大提高系统整体的并发能力以及性能。面对复杂业务模型并行程序会比串行程序更适应业务需求而并发编程更能吻合这种业务拆分。并发编程有什么缺点和劣势并发编程的目的就是为了能提高程序的执行效率提高程序运行速度但是并发编程并不总是能提高程序运行速度的而且并发编程可能会遇到很多问题比如**内存泄漏、上下文切换、线程安全、死锁**等问题。多线程的劣势线程也是程序所以线程需要占用内存线程越多占用内存也越多内存泄漏多线程需要协调和管理所以需要 CPU 时间跟踪线程线程之间对共享资源的访问会相互影响必须解决竞用共享资源的问题死锁问题。线程上下文切换可能消耗大量时间上下文切换当前线程时间片使用时间片后就会处于就绪状态并且让出CPU的使用权这就是CPU的上下文切换。线程和进程区别进程一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间一个进程可以有多个线程。线程进程中的一个执行任务控制单元负责当前进程中程序的执行。一个进程至少有一个线程一个进程可以运行多个线程多个线程可共享数据。根本区别进程是操作系统资源分配的基本单位而线程是处理器任务调度和执行的基本单位资源开销每个进程都有独立的代码和数据空间程序上下文程序之间的切换会有较大的开销线程可以看做轻量级的进程同一类线程共享代码和数据空间每个线程都有自己独立的运行栈和程序计数器PC线程之间切换的开销小。包含关系如果一个进程内有多个线程则执行过程不是一条线的而是多条线线程共同完成的线程是进程的一部分所以线程也被称为轻权进程或者轻量级进程。内存分配同一进程的线程共享本进程的地址空间和资源而进程之间的地址空间和资源是相互独立的影响关系一个进程崩溃后在保护模式下不会对其他进程产生影响但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮执行过程每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行必须依存在应用程序中由应用程序提供多个线程执行控制两者均可并发执行sleep 与 wait 区别对于sleep()方法我们首先要知道该方法是属于 Thread 类中的。而 wait()方法则是属于Object 类中的。sleep()方法导致了程序暂停执行指定的时间让出 cpu 该其他线程但是他的监控状态依然保持者当指定的时间到了又会自动恢复运行状态。在调用 sleep()方法的过程中线程不会释放对象锁。而当调用 wait()方法的时候线程会放弃对象锁进入等待此对象的等待锁定池只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。start 与 run 区别start() 方法来启动线程真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕 可以直接继续执行下面的代码。通过调用 Thread 类的 start()方法来启动一个线程 这时此线程是处于就绪状态 并没有运行。方法 run()称为线程体它包含了要执行的这个线程的内容线程就进入了运行状态开始运行 run 函数当中的代码。 Run方法运行结束 此线程终止。然后CPU 再调度其它线程synchronized 与Lock区别1. 直接区别synchronized 是Java关键字只提供非公平锁Lock是java.util.concurrent包下的接口默认非公平锁也可以实现公平锁2. 锁的获取和释放synchronized 自动获取和释放锁,Lock手动释放锁必须在 finally 代码块中显式调用 unlock() 方法释放锁。3.死锁问题在发生异常时会自动释放线程占有的锁因此不会导致死锁现象发生 而 Lock 在发生异常时如果没有主动通过 unLock()去释放锁则很可能造成死锁现象 因此使用 Lock 时需要在finally 块中释放锁。4.中断synchronized 不可中断Lock可以中断 中断方法 lockInterruptibly()5.性能早期版本 (JDK 1.5 及以前)synchronized 性能较差现在版本进行了大量优化引入偏向锁、轻量级锁、自旋锁、锁消除、锁粗化等与lock 性能差别不太大6.底层实现底层实现不一样 synchronized 是同步阻塞使用的是悲观并发策略lock 是同步非阻塞采用的是乐观并发策略7.条件绑定ReentrantLock 通过 Condition 可以绑定多个条件一个 ReentrantLock 可以创建多个 Condition 对象每个 Condition 相当于一个独立的等待区可以实现更精细的线程通信控制。synchronized只能配合一个等待队列wait/notify示例代码交替打印ABCpackagemain;importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.ReentrantLock;/** * ReentrantLock 多 Condition 示例 * * 场景三个线程交替打印 A、B、C * - 线程 1 只打印 A * - 线程 2 只打印 B * - 线程 3 只打印 C * * 每个 Condition 绑定一个特定的等待条件实现精准唤醒 */publicclassMultiConditionDemo{privatefinalReentrantLocklocknewReentrantLock();// 创建三个 Condition分别对应三个不同的等待条件privatefinalConditionconditionAlock.newCondition();privatefinalConditionconditionBlock.newCondition();privatefinalConditionconditionClock.newCondition();privateintstate1;// 当前应该打印的字母标识1A, 2B, 3CprivatefinalinttotalRounds5;// 总共执行几轮publicvoidprintA(){for(inti0;itotalRounds;i){lock.lock();try{// 如果当前不是打印 A 的时机进入 conditionA 等待while(state!1){conditionA.await();}System.out.print(A);state2;// 修改状态轮到 B 打印// 精准唤醒 conditionB 等待的线程conditionB.signal();}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{lock.unlock();}}}publicvoidprintB(){for(inti0;itotalRounds;i){lock.lock();try{// 如果当前不是打印 B 的时机进入 conditionB 等待while(state!2){conditionB.await();}System.out.print(B);state3;// 修改状态轮到 C 打印// 精准唤醒 conditionC 等待的线程conditionC.signal();}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{lock.unlock();}}}publicvoidprintC(){for(inti0;itotalRounds;i){lock.lock();try{// 如果当前不是打印 C 的时机进入 conditionC 等待while(state!3){conditionC.await();}System.out.print(C);state1;// 修改状态下一轮轮到 A 打印// 精准唤醒 conditionA 等待的线程conditionA.signal();}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{lock.unlock();}}}publicstaticvoidmain(String[]args){MultiConditionDemodemonewMultiConditionDemo();ThreadthreadAnewThread(demo::printA,Thread-A);ThreadthreadBnewThread(demo::printB,Thread-B);ThreadthreadCnewThread(demo::printC,Thread-C);threadA.start();threadB.start();threadC.start();try{threadA.join();threadB.join();threadC.join();}catch(InterruptedExceptione){e.printStackTrace();}System.out.println(\n执行完成);}}
返回列表