线程总结
线程:
面试题:https://blog.csdn.net/weixin_40205234/article/details/86645877
1.线程概念
2.创建线程方式
3.线程安全问题
解决方法之一就是用加锁,synchronized和显式锁。(还有三个同步工具类)
4.多种线程案例,例如DCL
5.wait , notify()
6.消费生产(卖票问题)
多线程就是为了提高程序效率。
上下文切换
任务从保存到再加载的过程就是一次上下文切换。上下文切换对系统来说意味着消耗大量的 CPU 时间,所以减少上下文切换的方法有:让步式上下文切换和抢占式上下文切换,
总之就是,减少锁的使用、使用CAS算法、减少线程使用、使用协程。
问题汇总:
1.有T1、T2、T3三个线程,如何保证T2在T1执行完后执行,T3在T2执行完后执行?
用join语句,在t3开始前join t2,在t2开始前join t1。
不过,这会破坏多线程的并发性,不建议这样做。
2.wait和sleep方法有什么不同?
- wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
- wait() 会释放锁,sleep() 不会。
3.notify和notifyAll方法有什么差别和联系?
都在synchronzied中执行,notify执行后会唤醒因调用wait方法而等待对象锁的其他线程,得到通知的线程就能继续得到对象锁从而继续执行下去
但notifyAll 执行后会去竞争对象锁,如果其中一个线程获得了对象锁,则会继续执行,在它退出synchronized代码释放锁后,其它的已经被唤醒的线程则会继续竞争,以此类推,直到所有被唤醒的线程都执行完毕
notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。
4.synchronized 和 ReentrantLock有什么不同?它们各自的适用场景是什么?
synchronized可以作用在方法和代码块上,但无法锁住由多个方法组成的业务块,而ReentrantLock可以保证业务层面的并发
5.Java中CyclicBarrier 和 CountDownLatch有什么不同?
CyclicBarrier 和 CountDownLatch 都可以用来让一组线程等待其它线程。与 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。
6.什么是线程安全?
所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
7.一个线程运行时发生异常会怎样?
如果该异常被捕获或抛出,则程序继续运行。
如果异常没有被捕获该线程将会停止执行
8.如何在两个线程间共享数据
每个线程执行的代码相同,可以使用同一个Runnable对象
每个线程执行的代码不同,用不同的Runnable对象
9.为什么wait, notify 和 notifyAll这些方法不在thread类里面?
由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。
10.Java中interrupted 和 isInterruptedd方法的区别?
interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会
11.为什么wait和notify方法要在同步块中调用?
因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。
12.volatile的作用:
使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效。Volatile 关键字的作用是变量在多个线程之间可见
volatile具有可见性、有序性,不具备原子性。
13. 什么是线程池? 为什么要使用它?
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池。 共有四种创建方法。调用他们的 execute 方法即可。
线程池的好处:
降低资源消耗、提高响应速度、提高线程的可管理性
线程池原理剖析:
提交一个任务到线程池中,线程池的处理流程如下:
1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程
3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个
14.如何避免死锁?
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
15. 怎么检测一个线程是否拥有锁?
在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。
16.如果你提交任务时,线程池队列已满。会时发会生什么?
事实上如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常。
17如果同步块内的线程抛出异常会发生什么?
无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我更喜欢同步块,因为它不用我花费精力去释放锁,该功能可以在finally block里释放锁实现。
18. Java多线程中调用wait() 和 sleep()方法有什么不同?
wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。
19.什么是多线程安全?
当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题.
20.什么是多线程死锁?
同步中嵌套同步,无法释放锁的资源。解决办法:同步中尽量不要嵌套。
21.如何停止线程?
使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。
使用 stop 方法强行终止线程(这个方法不推荐使用,因为 stop 和
suspend、resume 一样,也可能发生不可预料的结果)。
使用 interrupt 方法中断线程。 线程在阻塞状态
22.什么是守护线程
Java 中有两种线程,一种是用户线程,另一种是守护线程。
当进程不存在或主线程停止,守护线程也会被停止。
使用 setDaemon(true)方法设置为守护线程
23.join()方法作用
join 作用是让其他线程变为等待,只有当前线程执行完毕后,等待的线程
才会被释放。
24.说说 Java 内存模型
共享内存模型指的就是 Java 内存模型(简称 JMM),JMM 决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。
25.什么是 AtomicInteger
AtomicInteger 原子类。
26.多线程间的通信怎么实现
1.共享变量
2.wait() 。notify()