中科创达面试笔试题一卷

2016/08/03  |  from itroad.org  |  by leaf  |  浏览 189

一、 线程、进程和程序的区别

1、什么是线程

线程是进程的一个实体,是CPU调度和分配的基本单位,其本身不拥有系统资源,只含有程序计数器、寄存器和栈等一些运行时必不可少的基本资源。它的存在是为进程服务的,同属一个进程的线程共享进程所拥有的全部资源。

2、什么是进程

进程是具有一定独立功能的程序块关于某个数据集合上的一次运行活动,它是系统进行资源调度分配的一个独立单位。

3、什么是程序

程序是一组指令的集合,由多个进程共同完成,它是一个静态的实体,没有执行的含义。

4、线程和进程之间的区别

(1)线程是进程的一部分,因此线程有的时候被成为轻权进程或者轻量级进程;

(2)一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,那么进程的执行过程就不是由一条线(线程),而是由多条线(线程)共同完成的;

(3)系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。即除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源;

(4)与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少得多;

(5)进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。

5、进程与程序的区别

程序是一组指令的集合,是惊天的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般来说,一个进程一定与一个程序相对应,并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单的说,进程是程序的一部分,程序运行的时候会产生进程。

二、OSI七层网络模型

OSI(Open System Interconnection),开放式系统互联参考模型 。是一个逻辑上的定义,一个规范,它把网络协议从逻辑上分为了7层。每一层都有相关、相对应的物理设备,比如常规的路由器是三层交换设备,常规的交换机是二层交换设备。 各层的具体描述如下:

第七层:应用层

定义了用于在网络中进行通信和数据传输的接口 - 用户程式;提供标准服务,比如虚拟终端、文件以及任务的传输和处理;   

第六层:表示层

掩盖不同系统间的数据格式的不同性;指定独立结构的数据传输格式;数据的编码和解码;加密和解密;压缩和解压缩   

第五层:会话层

管理用户会话和对话;控制用户间逻辑连接的建立和挂断;报告上一层发生的错误   

第四层:传输层

管理网络中端到端的信息传送;通过错误纠正和流控制机制提供可靠且有序的数据包传送;提供面向无连接的数据包的传送;   

第三层:网络层

定义网络设备间如何传输数据;根据唯一的网络设备地址路由数据包;提供流和拥塞控制以防止网络资源的损耗   

第二层:数据链路层

定义操作通信连接的程序;封装数据包为数据帧;监测和纠正数据包传输错误   

第一层:物理层

定义通过网络设备发送数据的物理方式;作为网络媒介和设备间的接口;定义光学、电气以及机械特性。

三、DHCP为客户机提供的项目

DHCPOFFER(DHCP提供):

提供应答信息是DHCP服务器发送给DHCP客户端的第一个响应,它包含了IP地址、子网掩码、租用期(以小时为单位)和提供响应的DHCP服务器IP地址。

(当作为DHCP客户端的计算机第一次启动时,它需要经过DHCPDISCOVER、DHCPOFFER、DHCPREQUEST、DHCPAC四个步骤才能获得其TCP/IP配置信息,并得到IP地址的租期,具体参考书籍《计算机网络技术及应用》,朱金华,中国铁道出版社,第10章 常见网络服务 10.3 DHCP服务)

四、Internet内部保留IP地址

根据用途和安全性级别的不同,IP地址还可以大致分为两类:公共地址私有地址

  • 公用地址Internet中使用,可以在Internet中随意访问。
  • 私有地址只能在内部网络中使用,只有通过代理服务器才能与Internet通信。  

一个机构或网络要连入Internet,必须申请公用IP地址。但是考虑到网络安全和内部实验等特殊情况,在IP地址中专门保留了三个区域作为私有地址,其地址范围如下:   

  • A类:10.0.0.0/8:    10.0.0.0~10.255.255.255   
  • B类:172.16.0.0/12:  172.16.0.0~172.31.255.255   
  • C类:192.168.0.0/16:  192.168.0.0~192.168.255.255

使用保留地址的网络只能在内部进行通信,而不能与其他网络互连。因为本网络中的保留地址同样也可能被其他网络使用,如果进行网络互连,那么寻找路由时就会因为地址的不唯一而出现问题。但是这些使用保留地址的网络可以通过将本网络内的保留地址翻译转换成公共地址的方式实现与外部网络的互连。这也是保证网络安全的重要方法之一。

 

五、串行通信的方向性结构

串行数据通信的方向性结构有三种,即单工、半双工和全双工。

(1)单工数据传输只支持数据在一个方向上传输;

(2)半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;

(3)全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

六、线程生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程,其基本状态大体包括五种状态:

  • 新建(New) 当创建Thread类的一个实例(对象)且没有调用start()方法时,此线程进入新建状态(未被启动)。 例如:Thread t1=new Thread();
  • 就绪(Runnable) 线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();
  • 运行(Running) 线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
  • 堵塞(Blocked) 由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。再次状态下的线程仍然是“活的”,但是当前条件不允许其运行,如果某种时间出现,它便有可能返回可运行状态。
    • 正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
    • 正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
    • 被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
  • 死亡(Dead) 当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
    • 自然终止:正常运行run()方法后终止
    • 异常终止:调用stop()方法让一个线程终止运行

注意:

调用stop()或者destroy()方法也会使当前线程处于死亡状态,但是这种方法不被推荐,前者会产生异常,后者是强制终止,不会释放线程锁。线程一旦死亡,就不能复生。如果在一个死去的线程上调用start()方法,会抛出Java.lang.IllegalThreadStateException异常。

七、Synchronize关键字的用法以及在什么情况下使用

synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。

1、synchronized 方法

通过在方法声明中加入 synchronized关键字来声明 synchronized方法。如:

  1. public synchronized void accessVal(int newVal);
public synchronized void accessVal(int newVal);

synchronized方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)。在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized,以控制其对类的静态成员变量的访问。synchronized 方法的缺陷:若将一个大的方法声明为synchronized将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。

2、synchronized 块

通过 synchronized关键字来声明synchronized 块。语法如下:

  1. synchronized(syncObject) {
  2. //允许访问控制的代码
  3. }
synchronized(syncObject) {
    //允许访问控制的代码
}

synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject(如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。

notify、notifyAll、wait :
主要是为了解决持有监视器钥匙的线程暂停等待另一线程完成时可能发生死锁的问题。wait()方法使调用线程等待,直到发生超时或另一线程调用同一对象的notify()或notifyAll()方法。

wait() 方法的用法如下:wait()或wait(long timeoutPeriodInMilliseconds)前者等待被通知,后者等待超时或通知。线程调用wait()方法时,释放所持有的钥匙让另一等待线程进入监视区。notify()方法只唤醒一个等待线程,而notifyAll()唤醒所有等待该监视器的线程。注意,这些方法只能在监视区内调用。否则会输出一种RuntimeException类型的IllegaMonitorStateException异常状态。

总之wait()让线程等待,notify()和notifyall()激活某个等待线程,其实就是撤销该线程的中断状态,从而使他们有机会再次运行有时会遇到如下问题,程序的一部分在写数据,另一部分读数据,但有时会出现读部分超前写部分,这就是典型的产生者/消耗者问题.

  • .wait:是一个线程睡眠,直到在相同的对象上调用notify或notifyAll
  • .notify:启动第一个在相同对象调用wait的线程
  • .notifyAll:启动在相同的对象调用wait的所有线程

八、Overloaded和override的区别,overloaded是否可以改变返回值类型

方法的重写Overriding和重载Overloading是Java多态性的不同表现。

  • Overriding(重写是父类与子类之间多态性的一种表现,主要用于父类和子类之间的方法重写,即指定属性或方法可以在派生类中重写,在子类中定义某方法与其父类有相同的名称和参数,其参数列表要求相同。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
  • Overloading(重载是一个类中多态性的一种表现,它用于现有成员相同的名称来声明属性或方法,但参数列表与原始成员不同,它们或有不同的参数个数或有不同的参数类型。Overloaded的方法是可以改变返回值的类型。

九、sleep和wait的区别

  • sleep()方法:

Sleep是指休眠给定的时间,当这个时间达到之后,线程会再次醒来。

当程序运行到Thread.sleep(100L)时,休眠100毫秒,同时交出CPU时间片,100毫秒后,重新进入可运行状态,等待CPU重新分配时间片,而线程交出时间片时,CPU拿到时间片,由操作系统负责在可运行状态的线程中选中并分配时间片。

  • wait()方法:

Wait是等待状态,多长时间不清楚,由另一个线程将其唤醒。

程序在运行时,遇到wait()方法,这时线程进入当前对象的等待队列并交出CPU,等待其他线程notifyALL()时,才能重新回到可运行状态,等待OS分配CPU,带参数的wait()方法我也不是很清楚。

十、面向对象的特征

面向对象的三个基本特征是:封装、继承、多态。

o_OOBase.gif

(1)封装

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

(2)继承

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承概念的实现方式有三类:实现继承、接口继承和可视继承。

  • 实现继承是指使用基类的属性和方法而无需额外编码的能力;
  • 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
  • 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。

(3)多态

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

实现多态,有二种方式:覆盖,重载。

  • 覆盖,是指子类重新定义父类的虚函数的做法。
  • 重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

注意:

  继承与重载:一是子类与父类的关系,二是重载方法的调用问题。

十一、String和StringBuffer的区别

Java语言的字符串类主要有字符串常量类String、字符串变量类StringBuffer等。这两种字符串类都能采用顺序存储结构,能够存储任意长度的字符串,实现串的基本操作,并且能够识别序号越界等错误,对数组占用的存储空间进行控制,具有健壮性、安全性好等特点。

1、String类字符串常量)

java.lang.String类提供构造串对象、求串长、取字符、求子串、连接串等操作。String类以串常量方式存储和实现字符串操作,其字符数组容量等于串长,并且字符数组声明为最终变量,当构造串对象时对字符数组进行一次赋值,其后不能更改,因此String类不提供插入、删除子串操作。在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。

2、StringBuffer类字符串变量(线程安全)

java.lang.StringBuffer类以串变量方式实现字符串功能。其字符数组容量大于串长,并且能够修改,此时用一个整型变量len记载串的长度,对于多线程的操作是安全的。串变量的插入、删除操作与线性表相似,都要移动元素,不同的是,对串的操作一次处理一个子串。使用StringBuffer类则每次结果都会对StringBuffer对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用StringBuffer,特别是字符串对象经常改变的情况下。

2、StringBuilder类字符串变量(非线程安全)

java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与StringBuffer兼容的 API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,不同的是StringBuilder类是非线程安全的,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,在大多数实现中,它比StringBuffer要快,因为它少了很多的同步操纵。两者的方法基本相同。

十二、“==”和object.equal()的区别

==是一个关系运算符,用于判断两个基本数据类型(byte,short,char,int,long,float,double,boolean)的值是否相等,或两个引用变量的引用地址是否相等。

equals()是一个方法,用于判断引用变量引用地址指向的存储内容是否相等。equals()是Object类中定义的一个方法,由于其他引用类型默认继承Object,因此该方法在其他引用类型中都可以使用。

十三、字符串拼接的方法