1、简述进程和线程的异同
答:进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。一个应用程 序可以同时启动多个进程。例如对于IE浏览器程序,每打开一个IE浏览器窗口,就启动了一个新的进程。同样,每次执行JDK的java.exe程序,就启 动了一个独立的Java虚拟机进程,该进程的任务是解析并执行Java程序代码。
线程是指进程中的一个执行流程,有时也称为执行情景。一个进程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。 当进程内的多个线程同时运行时,这种运行方式称为并发运行。许多服务器程序,如数据库服务器和Web服务器,都支持并发运行,这些服务器能同时响应来自不 同客户的请求。
进程和线程的主要区别在于:每个进程都需要操作系统为其分配独立的内存地址空间,而同一进程中的所有线程在同一块地址空间中工作,这些线程可以共享同一块内存和系统资源,比如共享一个对象或者共享已经打开的一个文件。
2、编写多进程/多线程并发的程序时需要注意哪些方面?
答:编写并发的程序时应注意以下问题:
(1)、线程的优先级:线程的优先级代表该线程的重要程度,当有多个线程同时处于可执行状态并等待获得 CPU 时间时,线程调度系统根据各个线程的优先级来决定给谁分配 CPU 时间,优先级高的线程有更大的机会获得 CPU 时间,优先级低的线程也不是没有机会,只是机会要小一些罢了。
(2)、线程的阻塞:阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),在Java中人为的对线程进行阻塞时,应注意避免产生死锁。
(3)、同步对象的恒定性:不要对同步对象重新赋值,举个例子:
class A implements Runnable{
Object lock = new Object();
void run(){
for(...){
synchronized(lock){
// do something
...
lock = new Object();
}
}
}
run函数里面的这段同步代码实际上是毫无意义的。因为每一次lock都给重新分配了新的对象的reference,每个线程都在新的reference同步。所以,一般应该把同步对象声明为final.
final Object lock = new Object();
使用Singleton Pattern 设计模式来获取同步对象,也是一种很好的选择。
(4)、跨类的同步对象:但是对于复杂的问题,我们需要把问题分为几个部分来处理,需要几个不同的类来处理问题。这时,就需要在不同的类中,共享同步对象。比如,在生产者和消费者之间共享同步对象,在读者和写者之间共享同步对象。
如何在不同的类中,共享同步对象。有几种方法实现,
1、前面讲过的方法,使用static静态成员,(或者使用Singleton Pattern.)
2、用参数传递的方法,把同步对象传递给不同的类。
3、利用字符串常量的“原子性”。
对于第三种方法,这里做一下解释。一般来说,程序代码中的字符串常量经过编译之后,都具有唯一性,即,内存中不会存在两份相同的字符串常量。
(5)、同步的粒度:线程同步的粒度越小越好,即,线程同步的代码块越小越好。尽量避免用synchronized修饰符来声明方法。尽量使用 synchronized(anObject)的方式,如果不想引入新的同步对象,使用synchronized(this)的方式。而 且,synchronized代码块越小越好。
3、可采用哪些方法提高多进程/多线程并发程序的执行性能?
答:对多进程来说提高并发性能可以通过增加处理器的数量来提高并发性能;
对多线程来说,为了提高并发性能,应该使同步代码块中包含尽可能少的操作,使得一个线程能尽快释放锁,减少其他线程等待锁的时间。还可以在程序中使用线程池,减少创建和销毁线程的次数,从而提高性能。
4、简述进程和线程的优缺点。
答:进程的优点::①顺序程序的特点:具有封闭性和可再现性;②程序的并发执行和资源共享。多道程序设计出现后,实现了程序的并发执行和资源共享,提高了系统的效率和系统的资源利用率。
进程的缺点:操作系统调度切换多个线程要比切换调度进程在速度上快的多。而且进程间内存无法共享,通讯也比较麻烦。线程之间由于共享进程内存空间,所以交 换数据非常方便;在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
线程的优点:1)、它是一种非常"节俭"的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它 的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一 个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。当然,在具体的系统上,这个数 据可能会有较大的区别;2)、线程间方便的通信机制,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而 且方便;3)、使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上;4)、改善程序结构。一个既长又复 杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
线程的缺点:1.调度时, 要保存线程状态,频繁调度, 需要占用大量的机时;2.程序设计上容易出错(线程同步问题)。
5、针对什么样的需求,适合使用进程模式编程,什么样的适合线程?
答:a)当你要求数据安全性和不同任务之间的绝对隔离,或者不同任务之间没有互相访问的需求,使用进程方式
b)当你不同任务彼此需要经常协同工作,而效率又是考虑重点,需要用多线程,因为跨进程通信是个很开销很大的操作
6、 如何弥补他们的不足?在实际编程中可使用怎样的策略避免他们的缺点所带来的问题?
答:对进程来说,在硬件环境无法改变的情况下,可以将单一进程线程化,即将一个 进程分成多个线程来并发的执行,或者考虑其它的并发模型如多处理、协同例程、基于事件的编程、连续(continuation)、生成器等等(摘自 http://www128.ibm.com/developerworks/cn/linux/server/clinic/part5/index.html 作者Cameron)。
对线程来说,当前情况下可以采用线程池的方法,减少创建和销毁线程的次数,从而提高性能。