11.进程和线程的区别是什么?
https://www.cnblogs.com/alanfeng/p/5055141.html
http://blog.csdn.net/q_l_s/article/details/52608734
首先程序是静态的指令集合,而进程是运行中的指令集合。
进程是分配资源的基本单位,而线程是独立运行和调度的基本单位。
任意时刻,一个CPU只能运行一个进程,进程获得资源后进行分配,由不同的线程来执行和协作。
1. 进程:程序的一次执行
2. 线程:CPU的基本调度单位
一个进程的内存空间是可以被线程共享的。
进程的内存空间一般是独立的,而线程的内存空间一般是共享的,线程间的同步是为了防止竞争(因同时修改导致数据的不一致),所以要使用互斥锁,防止多个线程同时读写某一块内存区域。
还有的内存区域只允许固定个数的线程进入,就要使用信号量,防止线程之间产生冲突。
互斥锁止允许一个线程进入临界区,而信号量允许多个线程同时进入临界区。
在系统编程中,进程通信和线程同步内容以后有时间再查资料。
线程与进程的区别归纳:
a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
b.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
c.调度和切换:线程上下文切换比进程上下文切换要快得多。
d.在多线程OS中,进程不是一个可执行的实体。
进程定义:
进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
举一例说明进程:
想象一位有一手好厨艺的计算机科学家正在为他的女儿烘制生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原料:面粉、鸡蛋、糖、香草汁等。在这个比喻中,做蛋糕的食谱就是程序(即用适当形式描述的算法)计算机科学家就是处理器(cpu),而做蛋糕的各种原料就是输入数据。进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。现在假设计算机科学家的儿子哭着跑了进来,说他的头被一只蜜蜂蛰了。计算机科学家就记录下他照着食谱做到哪儿了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理蛰伤。这里,我们看到处理机从一个进程(做蛋糕)切换到另一个高优先级的进程(实施医疗救治),每个进程拥有各自的程序(食谱和急救手册)。当蜜蜂蛰伤处理完之后,这位计算机科学家又回来做蛋糕,从他离开时的那一步继续做下去。
线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。
假设,一个文本程序,需要接受键盘输入,将内容显示在屏幕上,还需要保存信息到硬盘中。若只有一个进程,势必造成同一时间只能干一样事的尴尬(当保存时,就不能通过键盘输入内容)。若有多个进程,每个进程负责一个任务,进程A负责接收键盘输入的任务,进程B负责将内容显示在屏幕上的任务,进程C负责保存内容到硬盘中的任务。这里进程A,B,C间的协作涉及到了进程通信问题,而且有共同都需要拥有的东西——-文本内容,不停的切换造成性能上的损失。若有一种机制,可以使任务A,B,C共享资源,这样上下文切换所需要保存和恢复的内容就少了,同时又可以减少通信所带来的性能损耗,那就好了。是的,这种机制就是线程。
线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。
12.创建线程有哪些方式?你更喜欢哪一种?为什么?
①继承Thread类(真正意义上的线程类),是Runnable接口的实现。
②实现Runnable接口,并重写里面的run方法。
③使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。
调用线程的start():启动此线程;调用相应的run()方法
继承于Thread类的线程类,可以直接调用start方法启动线程(使用static也可以实现资源共享).一个线程(对象)只能够执行一次start(),而且不能通过Thread实现类对象的run()去启动一个线程。
实现Runnable接口的类需要再次用Thread类包装后才能调用start方法。(三个Thread对象包装一个类对象,就实现了资源共享)。
线程的使用的话,注意锁和同步的使用。(多线程访问共享资源容易出现线程安全问题)
一般情况下,常见的是第二种。
* Runnable接口有如下好处:
*①避免点继承的局限,一个类可以继承多个接口。
*②适合于资源的共享
/*
* Thread的常用方法:
* 1.start():启动线程并执行相应的run()方法
* 2.run():子线程要执行的代码放入run()方法中
* 3.currentThread():静态的,调取当前的线程
* 4.getName():获取此线程的名字
* 5.setName():设置此线程的名字
* 6.yield():调用此方法的线程释放当前CPU的执行权(很可能自己再次抢到资源)
* 7.join():在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,
* A线程再接着join()之后的代码执行
* 8.isAlive():判断当前线程是否还存活
* 9.sleep(long l):显式的让当前线程睡眠l毫秒 (只能捕获异常,因为父类run方法没有抛异常)
* 10.线程通信(方法在Object类中):wait()
notify() notifyAll()
*
*设置线程的优先级(非绝对,只是相对几率大些)
* getPriority():返回线程优先值
* setPriority(int newPriority):改变线程的优先级
*/
13.线程的几种可用状态
1. 新建( new ):新创建了一个线程对象。
2. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 。
3. 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。
4. 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:
(一). 等待阻塞:运行( running )的线程执行 o . wait ()方法, JVM 会把该线程放 入等待队列( waitting queue )中。
(二). 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。
(三). 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。 当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。
5. 死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生
14.同步方法和同步代码块的区别是什么?
区别:
同步方法默认用this或者当前类class对象作为锁;
同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法;
同步方法使用关键字 synchronized修饰方法,而同步代码块主要是修饰需要进行同步的代码,用 synchronized(object){代码内容}进行修饰;
15.在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?
监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码。
16.什么是死锁(deadlock)?
所谓死锁是指多个进 程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。死锁产生的4个必要条件:
互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。
17.如何确保N个线程可以访问N个资源同时不发生死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。
18.Java集合类框架的基本接口有哪些?
Collection接口继承Iterable接口,其中继承的最重要的方法是iterator;
Interface Collection
|_ All Superinterfaces: Iterable
集合的基本类型为:一个一个元素存储的Collection和以键值对存储的Map;
Ps:无序的意思是放入什么顺序,拿出来的顺序随机;有序的意思是:放进去什么顺序,拿出来也是这个顺序;
Collection接口下: 有序可重复的List 和无序不可重复的Set接口;
Interface List
|_All Superinterface: Iterable,Collection
ArrayList: LinkedList:
|_java.lang.Object |_java.lang.Object
java.util.AbstractionCollectionjava.util.AbstractionCollection
java.util.AbstractList java.util.AbstractSequentialList
java.util.ArrayList java.util.LinkedList
Interface Set
|_All Superinterface: Iterable,Collection
HashSet: TreeSet(implements SortedSet):
|_java.lang.Object |_java.lang.Object
java.util.AbstractionCollectionjava.util.AbstractionCollection
java.util.AbstractionSet java.util.AbstractionSet
java.util.HashSet java.util.TreeSet
其中:(1). List接口的实现类为:ArrayList (底层采用数组存储,因此适合查询,不适合增删)、LinkedList(底层采用双向链表,适合增删,不适合查询);Vector不常用;
(2). Set接口的实现类为:HashSet(哈希表、散列表);SortedSet接口实现类---> TreeSet(无序,不可重复,但可按照元素大小自动排序,或者自定义排序方法);
Map接口下:以键值对为主,键值对无序不可重复;
HashMap:
|_ java.lang.Object
java.util.AbstractMap
java.util.HashMap
HashTable:
|_ java.lang.Object
java.util.Dictionary
java.util.HashTable
TreeMap(implements SortedMap):
|_java.lang.Object
java.util.AbstractMap
java.util.TreeMap
实现类: HashMap(哈希表,散列表,其中key等同于Set集合),HashTable(线程安全,效率低);
继承接口:SortedMap接口(无序,不可重复,但可按照元素大小自动排序,或者自定义排序方法)实现类--->TreeMap(其中的key集合为Set集合).
19.为什么集合类没有实现Cloneable和Serializable接口?
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。
20.什么是迭代器(Iterator)?
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。 Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。 (2) 使用next()获得序列中的下一个元素。 (3) 使用hasNext()检查序列中是否还有元素。 (4) 使用remove()将迭代器新返回的元素删除。 Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。