1、线程和进程的区别
线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,
一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。
线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,
每个请求分配一个线程来处理
2、实现线程有哪几种方式?
继承Thread类创建线程,实现Runnable接口创建线程,实现Callable接口通过FutureTask包装器来创建Thread线程,
使用ExecutorService、Callable、Future实现有返回结果的线程
3、线程有哪几种状态?它们之间如何流转的?
(https://zhidao.baidu.com/question/1738160030660108547.html)
Java中,每个线程都需经历新生、就绪、运行、阻塞和死亡五种状态,线程从新生到死亡的状态变化称为生命周期。
用new运算符和Thread类或其子类建立一个线程对象后,该线程就处于新生状态。
线程的生命周期,把图转化为文字就是:
1、线程通过new方法创建,调用start,线程进入就绪状态,等待系统的调度(时间片轮转调度)。
当系统调度,进入运行状态。正常结束或者异常退出,进程进入死亡状态。
2、处于运行状态的线程若遇到sleep,则线程进入睡眠状态,不会让出资源锁,sleep结束,
线程转为就绪状态,等待系统重新调度。
3、处于运行状态的线程可能在等待io,也可能进入挂起状态。io完成,转为就绪状态。
4、处于运行状态的线程yield,线程转为就绪状态。(yield只让给权限比自己高的)
5、处于运行状态的线程遇到wait,线程处于等待状态,需要notify()/notifyALL来唤醒线程,
唤醒后的线程处于锁定状态,获取了“同步锁”,之后,线程才转为就绪状态。处于运行的线程synchronized,
加上后 变成同步操作。处于锁定状态,获取了“同步锁”,之后,线程才转为就绪状态。
4、线程中的start()和run()方法有什么区别?
start()方法是线程类的方法,目的是开启线程
run()方法是线程任务方法,目的是写线程里面要做的事.
5、怎么终止一个线程?如何优雅地终止线程?
使用退出标识,使得线程正常退出,即当run方法完成后进程终止。
使用stop强行中断线程(此方法为作废过期方法),不推荐使用,暴力终止,可能使一些清理性的工作得不到完成。还可能对 锁定的内容进行解锁,容易造成数据不同步的问题。
this.interrupted():测试当前线程是否已经中断(静态方法)。如果连续调用该方法,则第二次调用将返回false。在api文档中说明interrupted()方法具有清除状态的功能。执行后具有将状态标识清除为false的功能。
this.isInterrupted():测试线程是否已经中断,但是不能清除状态标识。
6、ThreadLocal在多线程中扮演什么角色?
为每一个线程存一个本地变量.和多线程加锁比以空间换时间.
7、线程中的wait()和sleep()方法有什么区别?
sleep()不释放资源,仍然占用线程时间片.该方法是Thread类的方法
wait()释放资源,让出cpu使用权.该方法是Object类的方法
8、多线程同步有哪几种方法?
1、同步方法
即有synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
2、同步代码块
即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。
3、使用特殊域变量(volatile)实现线程同步
(1)volatile关键字为域变量的访问提供了一种免锁机制;
(2)使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新;
(3)因此每次使用该域就要重新计算,而不是使用寄存器中的值;
(4)volatile不会提供任何原子操作,它也不能用来修饰final类型的变量。
就是使用volatile修饰可能会被多个线程公用的变量,可能会出错的变量.
4、使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和块具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:
ReentrantLock() :创建一个ReentrantLock实例
lock() :获得锁
unlock() :释放锁
如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 。如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁。
5、使用局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
ThreadLocal与同步机制
a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题;
b.前者采用以”空间换时间”的方法,后者采用以”时间换空间”的方式。
9、什么是死锁?如何避免死锁?
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。
当然死锁的产生是必须要满足一些特定条件的:
1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
处理死锁的基本方法
1.预防死锁:通过设置一些限制条件,去破坏产生死锁的必要条件
2.避免死锁:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁
3.检测死锁:允许死锁的发生,但是通过系统的检测之后,采取一些措施,将死锁清除掉
4.解除死锁:该方法与检测死锁配合使用
10、多线程之间如何进行通信?
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
11、线程怎样返回结果?如何获取?
12、说说violatile关键字有什么用,和Synchronized有什么区别?
刷新内存,不读取缓存.每次变量更新都取最新的
13、假如新建T1、T2、T3三个线程,如何保证它们按顺序执行?
T1.start();
T1.join();
T2.start();
T2.join();
T3.start();
14、怎么控制同一时间只有3个线程运行?
使用只有三个线程的线程池
15、为什么要使用线程池?
节约频繁创建线程和释放资源的开支
16、说一说常用的几种线程池并讲讲其中的工作原理。
17、线程池启动线程submit()和execute()有什么不同?
JDK5往后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,它们的区别是:
execute(Runnable x) 没有返回值。可以执行任务,但无法判断任务是否成功完成。——实现Runnable接口
submit(Runnable x) 返回一个future。可以用这个future来判断任务是否成功完成。——实现Callable接口
18、说说多线程并发控制中的倒计时器、循环栅栏是什么,有什么应用场景?
19、什么是活锁、饥饿、无锁、死锁?
活锁这个概念大家应该很少有人听说或理解它的概念,而在多线程中这确实存在。活锁恰恰与死锁相反,死锁是大家都拿不到资源都占用着对方的资源,
而活锁是拿到资源却又相互释放不执行。当多线程中出现了相互谦让,都主动将资源释放给别的线程使用,这样这个资源在多个线程之间跳动而又得不到执行,这就是活锁。
我们知道多线程执行中有线程优先级这个东西,优先级高的线程能够插队并优先执行,这样如果优先级高的线程一直抢占优先级低线程的资源,
导致低优先级线程无法得到执行,这就是饥饿。当然还有一种饥饿的情况,一个线程一直占着一个资源不放而导致其他线程得不到执行,
与死锁不同的是饥饿在以后一段时间内还是能够得到执行的,如那个占用资源的线程结束了并释放了资源。
无锁,即没有对资源进行锁定,即所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。无锁典型的特点就是一个修改操作在一个循环内进行,
线程会不断的尝试修改共享资源,如果没有冲突就修改成功并退出否则就会继续下一次循环尝试。所以,如果有多个线程修改同一个值必定会有一个线程能修改成功,
而其他修改失败的线程会不断重试直到修改成功。
死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,而又相互等对方释放锁,此时若无外力干预,这些线程则一直处理阻塞的假死状态,形成死锁。
20、什么是原子性、可见性、有序性?
即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子性就像数据库里面的事务一样,他们是一个团队,同生共死。
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
即程序执行的顺序按照代码的先后顺序执行
21、什么是守护线程?有什么用?
守护线程
守护线程通常执行一些任务,当所有非守护线程终止的时候,JVM简单的丢弃掉所有现存的守护线程.一旦其它非守护线程执行完,不一定所有的守护线程都会执行完才退出,它们可能在非守护线程执行完后的某个时刻退出.
使用场景
来为其它线程提供服务支持.
守护线程的创建
为了创建一个守护线程,需要在调用thread.start()方法之前调用thread.setDeamon()方法.
22、怎么中断一个线程?如何保证中断业务不影响?
23、yield()方法有什么用?
理论上,yield意味着放手,放弃,投降。一个调用yield()方法的线程告诉虚拟机它乐意让其他线程占用自己的位置。这表明该线程没有在做一些紧急的事情。
注意,这仅是一个暗示,并不能保证不会产生任何影响。
让我们列举一下关于以上定义重要的几点:
Yield是一个静态的原生(native)方法
Yield告诉当前正在执行的线程把运行机会交给线程池中拥有相同优先级的线程。
Yield不能保证使得当前正在运行的线程迅速转换到可运行的状态
它仅能使一个线程从运行状态转到可运行状态,而不是等待或阻塞状态
24、什么是重入锁,和Synchronized锁有什么区别?
https://www.cnblogs.com/baizhanshi/p/7211802.html
25、Synchronized有哪几种用法?
同步方法
同步代码块
26、Fork/Join框架是干什么的?
Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架
https://www.cnblogs.com/senlinyang/p/7885964.html
27、如何给线程传递参数?
一、通过构造函数传递参数
二、通过变量和方法传递数据
三、通过回调函数传递数据
https://www.cnblogs.com/xql4j/articles/3242118.html
28、说说线程安全的和不安全的集合。
其中Vector、HashTable、Properties是线程安全的。其中ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。
(线程不安全是指:当多个线程访问同一个集合或Map时,如果有超过一个线程修改了ArrayList集合,则程序必须手动保证该集合的同步性。)
https://blog.csdn.net/weixin_40773253/article/details/78527660
29、什么是CAS算法?在多线程中有哪些应用。
https://blog.csdn.net/Jbinbin/article/details/86212688
30、你遇到过哪些多线程的问题?都是如何解决的?