锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

java面试题总结

时间:2022-11-18 10:30:00 dubox系列连接器

Java

JavaSE

线程

过程和线程的区别?

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

为什么要使用多线程?

答:提高程序效率

多线程创建方法?

答:继承Thread或Runnable 接口。

是继承Thread类好还是实现Runnable接口好?

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

多线程在哪里使用?

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

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

多线程安全是什么?

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

如何解决多线程之间的线程安全问题?

答:使用多线程同步或使(lock)

为什么使用线程同步或锁可以解决线程安全问题?

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

多线程之间的同步是什么?

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

同步代码块是什么?

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

多线程同步分类?

1.使用同步代码块?

synchronized(同一数据){

线程冲突可能会发生

}

privateObject mutex= newObject();// 自定义多线程同步锁

publicvoidsale() {

synchronized(mutex) {

if(trainCount> 0) {

try  {

Thread.sleep(10);

} catch (Exception e) {

}

System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");

trainCount--; }

}

}

 

2.使用同步函数

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

public synchronized void sale() {

if (trainCount > 0) {  

try {

Thread.sleep(40);

} catch (Exception e) {

}

System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");

trainCount--;

}

}

 

3.静态同步函数

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

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

同步代码块与同步函数区别?

答:

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

同步函数使用this锁

同步函数与静态同步函数区别?

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

答:

同步函数使用this锁

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

什么是多线程死锁?

答:

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

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

Wait()Notify ()区别?

Wait让当前线程有运行状态变为等待状态,和同步一起使用

Notify 唤醒现在正在等待的状态,和同步一起使用

Wait()sleep()区别?

对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

获取对象锁进入运行状态。

Lock与Synchronized区别

Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
*Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。

Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

Condition用法

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

代码:

Condition condition = lock.newCondition();

res. condition.await();  类似wait

res. Condition. Signal() 类似notify

Signalall notifyALL

 

如何停止线程?

  1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

    2.  使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。

3.  使用interrupt方法中断线程。 线程阻塞状态

什么是守护线程

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

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

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

join()方法作用

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

线程三特性

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

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

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

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

Java内存模型

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

 

 

什么是Volatile作用

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

什么是AtomicInteger

AtomicInteger原子类

什么ThreadLoca

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, 优先级)执行。

 

JDK1.5并发包

名称

作用

Lock

Executors

线程

ReentrantLock

一个可重入的互斥锁定 Lock,功能类似synchronized,但要强大的多。

Condition

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

 

ConcurrentHashMap

分段HasMap

AtomicInteger

原子

BlockingQueue

 

BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景

ExecutorService

 

执行器服务

锁的种类

自旋锁

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

public class SpinLock {

 

private AtomicReference 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机制控制多个线程对共享资源Lock接口及其实现类ReentrantLock

可重入锁

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

悲观

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

乐观锁

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

信号量

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

集合

 

网络编程

什么是Socket?

Socket就是为网络服务提供的一种机制。

通讯的两端都有Sokcet

网络通讯其实就是Sokcet间的通讯

数据在两个Sokcet间通过IO传输。

 

TCP与UDP在概念上的区别

udp: a、是面向无连接, 将数据及源的封装成数据包中,不需要建立建立连接

    b、每个数据报的大小在限制64k内

    c、因无连接,是不可靠协议

    d、不需要建立连接,速度快

tcp: a、建议连接,形成传输数据的通道.

    b、在连接中进行大数据量传输,以字节流方式

    c 通过三次握手完成连接,是可靠协议

d 必须建立连接m效率会稍低

设计模式

什么是设计模式?

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。本章系Java之美[从菜鸟到高手演变]系列之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师!

设计模式的分类?

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

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

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

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

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

 

 

设计模式的六大原则

1、开闭原则(Open Close Principle)

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

2、里氏代换原则(Liskov Substitution Principle)

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

3、依赖倒转原则(Dependence Inversion Principle)

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

4、接口隔离原则(Interface Segregation Principle)

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

5、迪米特法则(最少知道原则)(Demeter Principle)

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

6、合成复用原则(Composite Reuse Principle)

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

模式

什么是单例模式?

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

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

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

单例写法

 

 懒汉式代码

 

class SingletonTest {

public static void main(String[] args) {

Singleton sl1 = Singleton.getSingleton();

Singleton sl2 = Singleton.getSingleton();

System.out.println(sl1 == sl2);

}

}

 

public class Singleton {

// 当需要的才会被实例化

private static Singleton singleton;

 

private Singleton() {

 

}

 

synchronized public static Singleton getSingleton() {

if (singleton == null) {

singleton = new Singleton();

}

return singleton;

}

 

}

 

饿汉代码

class SingletonTest1 {

public static void main(String[] args) {

Singleton1 sl1 = Singleton1.getSingleton();

Singleton1 sl2 = Singleton1.getSingleton();

System.out.println((sl1 == sl2)+"-");

}

}

 

public class Singleton1 {

//当class 文件被加载初始化

private static Singleton1 singleton = new Singleton1();

 

private Singleton1() {

 

}

 

public static Singleton1 getSingleton() {

return singleton;

}

 

}

 

 

工厂模式

 什么工厂模式?

实现创建者和调用者分离

 简单工厂代码

public interface Car {

public void run();

}

public class AoDi implements Car {

@Override

public void run() {

     System.out.println("奥迪....");

}

}

public interface Car {

public void run();

}

 

 

public class CarFactory {

static public Car createCar(String carName) {

Car car = null;

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

car = new AoDi();

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

car = new BenChi();

}

return car;

 

}

public static void main(String[] args) {

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

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

car1.run();

car2.run();

}

}

 

  工厂方法

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

相关文章