资讯详情

java面试题总结

答:进程是所有线程的集合,每一个线程是进程中的一条执行路径,线程只是一条执行路径。

答:提高程序效率

答:继承Thread或Runnable 接口。

答:Runnable接口很好,因为接口可以继续继承。Thread类别不能再继承了。

答:提高程序效率主要体现在多线程上。

例如:分批发送短信、快雷多线程下载等。

答:同时共享多个线程,同一个,数据冲突可能发生在写作操作中,即线程安全。数据冲突不会发生在读取操作中。

答:使用多线程或使

答:数据冲突(线程不安全)可能会发生,。执行包裹代码后释放锁,然后执行其他线程。这样就可以解决线程不安全的问题。

答:当多个线程共享相同的资源时,不会受到其他线程的干扰。

答:包含可能出现线程安全问题的代码。只有当前的线程才能执行,包裹的代码才能释放,其他线程才能执行。

 

在方法上修饰synchronized 称为同步函数

 

方法上加上static关键字,使用synchronized 关键字修饰 为静态同步函数

静态的同步函数使用的锁是  该函数所属字节码文件对象

答:

同步代码使用自定锁(明锁)

同步函数使用this锁

注意:有些面试会这样问:例如现在一个静态方法和一个非静态静态怎么实现同步?

答:

同步函数使用this锁

静态同步函数使用字节码文件,也就是类.class

同步中嵌套同步,无法释放锁的资源。

解决办法:同步中尽量不要嵌套同步

 Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能,

 

  

Java中有两种线程,一种是用户线程,另一种是守护线程。

 当进程不存在或主线程停止,守护线程也会被停止。

 使用setDaemon(true)方法设置为守护线程

join作用是让其他线程变为等待,只有当前线程执行完毕后,等待的线程才会被释放。

多线程有三大特性,原子性、可见性、有序性

原子性:保证数据一致性,线程安全。

可见性:对另一个线程是否课件

有序性:线程之间执行有顺序

共享内存模型指的就是Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

 

 

Volatile 关键字的作用是变量在多个线程之间可见。

AtomicInteger原子类

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。

 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

void set(Object value)设置当前线程的线程局部变量的值。

public Object get()该方法返回当前线程所对应的线程局部变量。

public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

 

 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。

基于以下几个原因在多线程应用程序中使用线程是必须的:

  1. 线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。

  2. 线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

  3. 线程池根据当前在系统中运行的进程来优化线程时间片。

  4. 线程池允许我们开启多个任务而不用为每个线程设置属性。

  5. 线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

  6. 线程池可以用来解决处理一个特定请求最大线程数量限制问题。

 

Java通过Executors(jdk1.5并发包)提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

 

名称

作用

 

 

 

自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区。如下

public class SpinLock {

 

private AtomicReference<Thread> sign = new AtomicReference<>();

 

public void lock() {

Thread current = Thread.currentThread();

while (!sign.compareAndSet(null, current)) {

}

}

 

public void unlock() {

Thread current = Thread.currentThread();

sign.compareAndSet(current, null);

}

}

 

所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源

可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁

.悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系 统不会修改数据)。

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。 而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如 果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。 

 

 

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:

 

 

开闭原则就是说。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

原则是尽量使用合成/聚合的方式,而不是使用继承。

 单例保证一个对象JVM中只能有一个实例,常见单例 懒汉式、饿汉式

 什么是懒汉式,就是需要的才会去实例化,线程不安全。

 什么是饿汉式,就是当class文件被加载的时候,初始化,天生线程安全。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  CarFactory {

  Car createCar(String carName) {

Car car = ;

 (carName.equals("奥迪")) {

car =  AoDi();

}   (carName.equals("奔驰")) {

car =  BenChi();

}

 car;

 

}

   main(String[] args) {

Car car1 = CarFactory.createCar("奥迪");

Car car2 = CarFactory.createCar("奔驰");

car1.run();

car2.run();

}

}

 

标签: dubox系列连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台