java基础知识扫盲

一、string为何不可继承?html

答:由于string是用final修饰的不可变类,不能够被继承;java

       为何要用final修饰?android

答:安全,设计者将string设为共享的,子类不能够修改,所以设置为final;web

       效率,共享的效率更高;算法

       StringStringBufferStringBuilder区别数据库

答:运行速度StringBuilder>StringBuffer>String,String为字符串常量,一旦建立对象后不可更改;然后者是可更改的;编程

       线程安全上StringBuffer是线程安全的,StringBuilder是非线程安全的。跨域

二、怎样减小线程的上下文切换?数组

答:减小并发线程数,尽可能使用无锁编程,CAS算法浏览器

       什么是CAS算法?

答:compare and swap意思是先比较旧的预期值和原来内存中存储的值相等,再更改成目标值,是一种乐观锁,适用于读多写少的状况,效率较高,只有极少的状况会发生冲突

       CAS会有ABA问题应怎么解决?

答:ABA问题是指旧的预期值被更改成和原来内存中存储的值相等,已经发生过一次更改,这种状况能够经过版本号(AtomicStampedReference)、时间戳来解决,比较最初获取的版本号和更改前获取的版本号是否一致,一致则更改,更改后都将版本号+1

三、说下volatile关键字的做用?

答:可见性:当多个线程共同访问同一变量,当其中一个线程修改了该变量,其余线程都能马上看到修改的值

       有序性:防止指令重排序,程序执行顺序按当前代码顺序执行

       注:指令重排序不会影响单个线程的执行,但会影响多个线程并发执行的结果

       https://www.cnblogs.com/dolphin0520/p/3920373.html

内存屏障会提供3个功能:

  1)它确保指令重排序时不会把其后面的指令排到内存屏障以前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操做已经所有完成;

  2)它会强制将对缓存的修改操做当即写入主存;

  3)若是是写操做,它会致使其余CPU中对应的缓存行无效。

      volatile能够保证原子性吗?

答:不是,两个线程同时从内存中读取变量的值i=10到本身的工做内存,线程a和线程b同时作自增操做+1,写入工做内存,再写入主内存,两个线程分别自增一次,但主内存中的结果只增长1,所以volatile不保证原子性

四、描述下java内存模型

答:Java内存模型规定全部的变量都是存在主存当中,每一个线程都有本身的工做内存。线程对变量的全部操做都必须在工做内存中进行,而不能直接对主存进行操做。而且每一个线程不能访问其余线程的工做内存。

五、描述下happens-before原则(先行发生原则)

答:Java内存模型具有一些先天的“有序性”

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操做先行发生于书写在后面的操做
  • 锁定规则:一个unLock操做先行发生于后面对同一个锁额lock操做
  • volatile变量规则:对一个变量的写操做先行发生于后面对这个变量的读操做
  • 传递规则:若是操做A先行发生于操做B,而操做B又先行发生于操做C,则能够得出操做A先行发生于操做C
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个一个动做
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 线程终结规则:线程中全部的操做都先行发生于线程的终止检测,咱们能够经过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

六、ThreadLocal 原理

定义:线程局部变量,为每个线程都提供了一份变量副本,每个线程均可以随意修改本身的变量副本,而不会对其余线程产生影响;

实现:在ThreadLocal类中有一个静态内部类ThreadLocalMap(其相似于Map),用键值对的形式存储每个线程的变量副本,ThreadLocalMap中元素的key为当前ThreadLocal对象,而value对应线程的变量副本,每一个线程可能存在多个ThreadLocal。

应用:采用了“以空间换时间”的方式,解决多线程数据共享问题,实际过程当中应用到了数据库链接。

问题:ThreadLocal有可能产生内存泄漏,由于map中的key弱引用指向ThreadLocal,当把threadlocal实例置为null之后,没有任何强引用指向threadlocal实例,因此threadlocal将会被gc回收. 可是,咱们的value却不能回收,由于存在一条从current thread链接过来的强引用。

七、synchronized锁怎么实现的?

答:synchronized锁存在Java对象头里,每个被锁住的对象都会和一个monitor对象关联;

       执行monitorenter获取锁,读取monitor对象的count字段,count==0,则获取锁成功且count+1;

       执行monitorexit指令时将count-1,若count==0,则释放锁;

synchronized为何是重量级锁?

答:重量级锁经过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操做系统的Mutex Lock实现,操做系统实现线程之间的切换须要从用户态到内核态的切换,切换成本很是高。

八、Lock锁怎么实现的?

ReentrantLock是基于AQS实现的,AQS的基础是CAS

AbstractQueuedSynchronizer,简称AQS,基于volatile int state +FIFO队列(双端队列)实现的,

ReentrantLock中有一个抽象类Sync根据传入构造方法的布尔型参数实例化出Sync的实现类FairSync和NonfairSync,并重写tryAcquire(int arg)和tryRelease(int arg)两个方法。

lock()利用CAS去判断state是否是0,若是state=0,则获取锁,state设为1并将当前线程设为主;

若是state非0,执行acquire()->tryAcquire()->(非公平锁)若是state=0,CAS尝试获取锁,若加锁成功state设为1并将当前线程设为主,

                                                                                         state非0,判断当前owner是不是当前线程,若是是,state+1,返回true,若是不属于当前线程,返回false,则添加FIFO等待队列队尾。

                                                                    (公平锁)若是state=0,hasQueuedPredecessors()判断当前是否有等待的线程, 若是没有使用CAS尝试获取锁,若加锁成功state设为1并将当前线程设为主,

                                                                                     state非0,判断当前owner是不是当前线程,若是是,state+1,返回true,若是不属于当前线程,返回false,则添加FIFO等待队列队尾。

ReentrantLock获取锁定与三种方式:

    a)  lock(), 若是获取了锁当即返回,若是别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁;

    b) tryLock(), 若是获取了锁当即返回true,若是别的线程正持有锁,当即返回false;

    c)tryLock(long timeout,TimeUnit unit),若是获取了锁定当即返回true,若是别的线程正持有锁,会等待参数给定的时间,在等待的过程当中,若是获取了锁定,就返回true,若是等待超时,返回false;

    d)lockInterruptibly():若是获取了锁定当即返回,若是没有获取锁,当前线程处于休眠状态,直到获取锁,或者当前线程被别的线程中断;

九、synchronizedLock什么区别?

类别 synchronized Lock
存在层次 Java的关键字,在jvm层面上 经过代码实现,是一个类
锁的释放 会自动释放锁定(代码执行完成或者出现异常) 不会主动释放,必须将unLock()放到finally{}中
锁的获取 假设A线程得到锁,B线程等待。若是A线程阻塞,B线程会一直等待 分状况而定,Lock有多个锁获取的方式,具体下面会说道,大体就是能够尝试得到锁,线程能够不用一直等待
锁状态 没法判断 能够判断
锁类型 可重入,不可中断,非公平 可重入,可中断,可公平(二者皆可)
性能 少许同步 大量同步

十、线程池有哪几种?

答:Java经过Executors提供四种线程池,分别为:

一、newCachedThreadPool:建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。(线程最大并发数不可控制)SynchronousQueue

二、newFixedThreadPool:建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。LinkedBlockingQueue

三、newScheduledThreadPool:建立一个定长线程池,支持定时及周期性任务执行。

四、newSingleThreadExecutor:建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。LinkedBlockingQueue

       线程池参数有哪些?

答:ThreadPoolExecutor构造方法

public ThreadPoolExecutor(int corePoolSize,//核心线程池大小

                              int maximumPoolSize,//最大线程池大小

                              long keepAliveTime,//线程池中超过corePoolSize数目的空闲线程最大存活时间;能够allowCoreThreadTimeOut(true)成为核心线程的有效时间

                              TimeUnit unit,//keepAliveTime的时间单位

                              BlockingQueue<Runnable> workQueue,//阻塞任务队列

                              ThreadFactory threadFactory,//线程工厂

                              RejectedExecutionHandler handler) {//当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理

      线程池的工做过程?

答:1.当线程池小于corePoolSize时,新提交任务将建立一个新线程执行任务,即便此时线程池中存在空闲线程;

2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行;

3.workQueue已满,且当前线程数大于corePoolSize且小于maximumPoolSize时,新提交任务会建立新线程执行任务;

4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理;

5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程;

6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭;

  线程池拒绝策略有几种?

答:ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,可是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,而后从新尝试执行任务(重复此过程)

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

  线程池相关的几个队列:

答:ArrayBlockingQueue, 一个由数组结构组成的有界阻塞队列fifo;默认状况下不保证公平阻塞,能够经过配置建立公平阻塞的队列,实现原理是可重入锁。

LinkedBlockingQueue,一个由链表结构组成的有界阻塞队列 fifo,LinkedBlockingQueue 可无界,也能够有界,初始化指定长度则为有界,不指定则为无界

PriorityBlockingQueue,一个支持优先级排序的无界阻塞队列

synchronousQueue,一个不存储元素的阻塞队列

十一、线程状态有几种?

答:线程的生命周期为5个状态,新建状态、就绪状态(start)、运行状态(run)、阻塞状态和死亡状态。

运行的线程执行sleep线程进入阻塞状态,sleep时间到了之后进入就绪状态。

线程的实现由3种方法:继承Tread类;实现Runnable接口;实现Callable接口

Sleep和wait的区别:sleep属于Thread类,wait属于Object类,

                               sleep线程不会释放对象锁,wait会释放对象锁;

                               wait须要调用notify()方法后本线程才进入对象索定池(只能同步方法或同步代码块中使用),sleep结束后进入就绪状态。

notify()与notifyAll()的区别:notify()随机通知一个线程;

                                              notifyAll()通知全部线程;

十一、Java8新特性

答:(1) lambda表达式 (2) Stream,处理集合数据(3) 接口default方法,有利于数据移植

十二、抽象类和接口

答:抽象类和抽象方法都须要被abstract修饰,抽象方法必定要定义在抽象类中。抽象类全部方法都是抽象方法的时候,彻底能够用接口实现。抽象类为部分方法提供实现,避免了子类重复实现这些方法,提供了代码重用性。单继承,多实现。既要定义子类的行为,又要为子类提供共性功能时才选用抽象类。

1三、内部类

静态内部类:static修饰,能够访问外部类全部的静态变量和方法。应用场景如hashmap的静态内部类entry

成员内部类:能够访问外部类全部的变量和方法。和静态内部类不一样,成员内部类的实例都依赖外部类的实例。

局部内部类:即定义在方法中的类,能够访问外部类的全部变量和方法,若是局部内部类用static修饰方法内,则只能访问外部类的static变量

匿名内部类:匿名内部类能够出如今任何容许表达式出现的地方,定义格式为new 类/接口。应用场景,分布式工具类,多线程,android中的绑定监听事件。

1三、反射

反射是java在运行状态下,对于任意一个类,都可以知道这个类的全部属性和方法;

优势是能够动态建立对象和编译;缺点是对性能有影响。

获取方式有3种:类名.class,Class.forName(xxx); new 类名.getclass()。

反射的应用场景有:反编译、mybatis底层实现、工具类,bean转map,经过反射获取注解,能够作一些校验

1四、java面向对象的三大特性

  继承:是对有共同特性的多类事物,进行再抽象成一个类。java继承是extends关键字,子类中有和父类中可访问的同名同返回同参数列表的方法时,就会覆盖从父类继承来的方法

  封装:隐藏对象的属性和实现细节,仅对外提供接口。java中的类属性访问权限不是private,要想隐藏该类方法须要用private修饰符

  多态:两种机制:编译时多态和运行时多态.

  方法重载,方法名相同,其余不一样,编译时重载。方法重写(覆盖),子类覆盖父类的方法。

1五、泛型

泛型只在编译阶段有效,在编译过程当中,正确检测泛型结果后,会将泛型的相关信息擦除,而且添加类型检测和类型转换。

使用泛型的好处是:类型安全;消除强制类型转换,提升性能。

泛型的具体使用有3种方式:

(1) 泛型类,例如hashmap<K,V>,其中key和value只在运行时才会真正根据类型来构造和分配内存

(2) 泛型接口,当2个接口的处理方式一致,只是对象不一样的时候,能够用泛型接口

(3) 泛型方法,把方法参数泛型话

1六、join是怎么实现的?

join是thread类synchronized修饰的同步方法,其使用wait()方法实现等待;

 1七、异常

1、error

程序没法处理的错误,比较严重的问题,虚拟机错误,如OutOfMemoryError、NoClassDefFoundError

2、exception

一、已检查异常

编译器要求必须对代码try catch或者throw expetion,如IOException、SQLException、FileNotFoundException、ParseException

二、未检查异常(RuntimeException运行时异常)

编译时不检查,运行时可能发生的异常,如NullPointerException,IndexOutOfBoundsException

1八、有return的状况下try catch finally的执行顺序:

 (1)无论有没有出现异常,当执行到try内时,finally块中代码都会执行;
 (2)当try和catch中有return时,finally仍然会执行;
  (3)finally是在return后面的表达式运算后执行的(此时并无返回运算后的值,而是先把要返回的值保存起来,无论finally中的代码怎么样,返回的值都不会改变(对象类型须要另外分析),仍然是以前保存的值),因此函数返回值是在finally执行前肯定的;
  (4)finally中最好不要包含return,不然程序会提早退出,返回值不是try或catch中保存的返回值。

1九、对象的初始化顺序:

(1)类加载以后,按从上到下(从父类到子类)执行被static修饰的语句;

(2)当static语句执行完以后,再执行main方法;

(3)若是有语句new了自身的对象,将从上到下执行构造代码块、构造器(二者能够说绑定在一块儿)。

20、cookie与session

Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的链接就会关闭,再次交换数据须要创建新的链接。这就意味着服务器没法从链接上跟踪会话。要跟踪该会话,必须引入一种机制。

Cookie就是这样的一种机制。它能够弥补HTTP协议无状态的不足。在Session出现以前,基本上全部的网站都采用Cookie来跟踪会话。

Cookie其实是一小段的文本信息。客户端请求服务器,若是服务器须要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。

Cookie具备不可跨域名性。

ookie生命周期默认为浏览器会话期间,驻留内存,关闭浏览器cookie就没了
设置cookie的过时时间为永不过时,将cookie保存在硬盘上

首先浏览器请求服务器访问web站点时,程序须要为客户端的请求建立一个session的时候,服务器首先会检查这个客户端请求是否已经包含了一个session标识、称为SESSIONID,若是已经包含了一个sessionid则说明之前已经为此客户端建立过session,服务器就按照sessionid把这个session检索出来使用,若是客户端请求不包含session id,则服务器为此客户端建立一个session而且生成一个与此session相关联的session id,sessionid 的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionid将在本次响应中返回到客户端保存,保存这个sessionid的方式就能够是cookie,这样在交互的过程当中,浏览器能够自动的按照规则把这个标识发回给服务器,服务器根据这个sessionid就能够找获得对应的session,又回到了这段文字的开始

关闭浏览器不会致使session被删除,迫使服务器为seesion设置了一个失效时间,通常是30分

当浏览器将cookie禁用,基于cookie的session将不能正常工做,每次使用request.getSession() 都将建立一个新的session。达不到session共享数据的目的,可是咱们知道原理,只须要将session id 传递给服务器session就能够正常工做的。

解决:经过URL将session id 传递给服务器:URL重写

2一、通讯方式

1、进程间的通讯方式
# 管道( pipe ):管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用。进程的亲缘关系一般是指父子进程关系。
# 有名管道 (namedpipe) : 有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。
# 信号量(semophore ) : 信号量是一个计数器,能够用来控制多个进程对共享资源的访问。它常做为一种锁机制,防止某进程正在访问共享资源时,其余进程也访问该资源。所以,主要做为进程间以及同一进程内不一样线程之间的同步手段。
# 消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 (sinal ) : 信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生。
# 共享内存(shared memory ) :共享内存就是映射一段能被其余进程所访问的内存,这段共享内存由一个进程建立,但多个进程均可以访问。共享内存是最快的 IPC 方式,它是针对其余进程间通讯方式运行效率低而专门设计的。它每每与其余通讯机制,如信号量,配合使用,来实现进程间的同步和通讯。
# 套接字(socket ) : 套解口也是一种进程间通讯机制,与其余通讯机制不一样的是,它可用于不一样及其间的进程通讯。


2、线程间的通讯方式

# 锁机制:包括互斥锁、条件变量、读写锁
*互斥锁提供了以排他方式防止数据结构被并发修改的方法。
*读写锁容许多个线程同时读共享数据,而对写操做是互斥的。
*条件变量能够以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一块儿使用。
# 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
# 信号机制(Signal):相似进程间的信号处理
线程间的通讯目的主要是用于线程同步,因此线程没有像进程通讯中的用于数据交换的通讯机制。

2二、使用DateTimeFormatter

若是是Java8应用,可使用DateTimeFormatter代替SimpleDateFormat,这是一个线程安全的格式化工具类。

相关文章
相关标签/搜索