『来源:HollisChuang』
1、进程和线程的区别
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每一个进程都有一个自己的地址空间。进程具有一定的独立功能。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程在程序中是独立的并发的执行流。
线程自己不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源,线程只拥有一点在运行中必不可少的资源,比如:自己的堆栈、自己的程序计数器和自己的局部变量。
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。线程的执行时抢占式的,也就意味着当前运行的线程在任何时候都有可能被挂起,以便另外一个线程可以运行。
区别:
① 一个程序至少有一个进程,一个进程至少有一个线程
② 内存共享:进程在执行过程中拥有独立的内存单元(一个进程崩溃后,在保护模式下不会对其它进程产生影响);
而多个线程共享进程提供的内存(拥有自己的私有栈空间只是作为运行需要的极少内存),从而极大地提高了程序的运行效率,但一个线程死掉就等于整个进程死掉。所以多进程的程序要比多线程的程序健壮
③ 因为线程的划分尺度小于进程,使得多线程程序的并发行高。
④ 执行过程:进程独立执行;线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
⑤ 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。
但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
参考链接
https://blog.csdn.net/mxsgoden/article/details/8821936
2、并行和并发的区别和联系
并行:是指在同一时刻,有多条指令在多个处理器上同时执行。
并发:是指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
3、同步和异步
同步:可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步:执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,通过状态、通知和回调来通知调用者,从而完成一个完整的流程。
同步在一定程度上可以看做是单线程,这个线程请求一个方法后就待这个方法给他回复,否则他不往下执行(死心眼)。
异步在一定程度上可以看做是多线程的,请求一个方法后,就不管了,继续执行其他的方法,等有返回值以后,再回来执行程序
4、多线程的实现方式,有什么区别
实现方式:
① 继承Thread
类
继承Thread
类,重写run()
方法,实例化线程类,调用start()
方法启动线程。
② 实现Runnable
接口
实现Runnable
接口并重写run()
方法,创建Runnable
实例,并以此实例作为Thread
类的target
参数创建Thread
对象,调用Thread
对象的start()
启动线程
③ 使用Callable
接口和Future
来创建线程
实现Callable
接口,并实现call()
方法,并创建Callable
实例,然后使用FutureTask
对象来包装Callable
实例,使用FutureTask
对象作为Thread
的target
来创建并启动线程
区别:
Runnable
接口和Callable
接口的方式基本相同(实现Runnable
接口和Callable
接口仅仅是创建了一个任务,但是仍然需要Thread
类来创建线程并启动),他俩唯一区别只是Callable
接口实现方法有返回值,并且也可以声明抛出异常而已,可以归为一类。
1、继承Thread
实现线程
① 已经继承了Thread
类,不能继承其他类
② 获取当前线程,可以直接使用this
来获得
2、实现Runnable
接口、Callable
接口创建线程
①实现的是接口,还可以继承其他类
② 多个线程可以共享同一个target
对象,适合多个相同的线程来处理同一份资源的情况
③ 获取当前线程必须用Thread.currentThread()
方法来获得
5、什么叫守护线程
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。
守护线程, 是指在程序运行的时候在后台提供一种通用服务的线程, 比如垃圾回收线程就是一个很称职的守护者。
并且这种线程并不属于程序中不可或缺的部分。因此只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
可以通过调用线程的setDaemon()
方法,传入参数true,将一个用户线程设置为一个守护线程
这里有几点需要注意:
(1) thread.setDaemon()
必须在thread.start()
之前设置,否则会跑出一个IllegalThreadStateException
异常。你不能把正在运行的常规线程设置为守护线程。
(2) 在Daemon线程中产生的新线程也是Daemon的。
(3) 不要认为所有的应用都可以分配给Daemon来进行服务,比如读写操作或者计算逻辑。 因为你不可能知道在所有的User完成之前,Daemon是否已经完成了预期的服务任务。一旦User退出了,可能大量数据还没有来得及读入或写出,计算任务也可能多次运行结果不一样。这对程序是毁灭性的。
6、如何停止一个线程?
① 设置一个标志位 需要用volatile
来修饰,保证线程读取时标志位是最新数据
② 在sleep
状态下使用interrupt()
方法,程序抛出InterruptedException
,捕捉这个异常来结束程序。但仍要调用Thread.currentThread().interrupt()
恢复中断,让线程退出。
7、什么是线程安全?
线程安全就是多线程访问同一代码,不会产生不确定的结果。
如何保证线程安全
对非安全的代码进行加锁控制;
使用线程安全的类;
多线程并发情况下,线程共享的变量改为方法级的局部变量。
https://blog.csdn.net/suifeng3051/article/details/52164267
8、synchronized 和 lock的区别
主要相同点:
Lock能完成synchronized所实现的所有功能
主要不同点:
Lock有比synchronized更精确的线程语义和更好的性能。
Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。
Lock锁的范围有局限性,块范围,而synchronized可以锁住块、对象、类。
9、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
现在分两种情况来讨论:
1.当前线程调用的是synchronized普通方法(相对于static方法);
2.当前线程调用的是synchronized static方法。
1.当前线程调用的是synchronized普通方法(相对于static方法)时,其它线程是否可进入此对象的其它方法:
1)其它方法是加了synchronized的普通方法,不能;
2)其它方法是没加synchronized的普通方法,能;
3)其它方法是synchronized的static方法,能;
4)其它方法是没加synchronized的static方法,能。
5)如果这个方法内部调用了wait,则可以进入其他synchronized方法。
(因为当前线程执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步器)
2.当前线程调用的是synchronized static方法,其它线程是否可进入此对象的其它方法:
1)其它方法是加了synchronized的普通方法,能;
2)其它方法是没加synchronized的普通方法,能;
3)其它方法是synchronized的static方法,不能;
4)其它方法中有synchronized(xxx.class)的,不能;
5)其它方法是没加synchronized的static方法,能。
所谓的synchronized(xxx.class)就是同步代码块:
public void method5(){
synchronized(xxx.class){
System.out.println("this is a synchronized static method——method5.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
参考链接:java线程之——synchronized的注意细节
10、启动一个线程是用run()还是start()?
启动一个线程是使用star(),启动线程后,系统会把该线程的run()方法当成线程执行体来处理。
如果使用的是run()方法,则run()方法会被立即执行,而且在run()方法返回之前其他线程无法并发执行。
因此如果直接调用线程对象的run()方法,系统会把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程体。
11、wait和sleep的区别
sleep()方法是Thread类中方法,而wait()方法是Object类中的方法。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是它的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。
12、notify()和notifyAll()的区别
notify():
唤醒在次同步监视器上等待的单个线程,如果所有线程都在此同步监视器上等待,则会选择唤醒其中一个线程。
选择是任意性的。只有当前线程放弃对该同步监视器的锁定后(使用wait()方法),才可以执行被唤醒的线程
notifyAll():
唤醒在此同步监视器上等待的所有线程。只有当前线程放弃该同步监视器的锁定后,才可以执行被唤醒的线程。