面试官常问的 Java 基础题(五)

41.给我六个你最常见到的 runtime exception。

NullPointerException 、 IndexOutOfBoundsExcention 、IOException 、ClassNotFoundException 、InterruptedException 、IllegalThreadException

异常说明
ArithmeticException由于除数为0引起的异常
ArrayStoreException由于数组存储空间不够引起的异常
ClassCastException当把一个对象归为某个类,但实际上此对象并不是由这个类创建的,也不是其子类创建的,则会引起异常
IllegalMonitorStateException监控器状态出错引起的异常
NegativeArraySizeException数组长度是负数,则产生异常
NullPointerException程序试图访问一个空的数组中的元素或访问空的对象中的方法或变量时产生异常
OutofMemoryException用new语句创建对象时,如系统无法为其分配内存空 间则产生异常
SecurityException由于访问了不应访问的指针,使安全性出问题而引起异常
IndexOutOfBoundsExcention由于数组下标越界或字符串访问越界引起异常
IOException由于文件未找到、未打开或者I/O操作不能进行而引起异常
ClassNotFoundException未找到指定名字的类或接口引起异常
CloneNotSupportedException程序中的一个对象引用Object类的clone方法,但 此对象并没有连接Cloneable接口,从而引起异常
InterruptedException当一个线程处于等待状态时,另一个线程中断此线程,从而引起异常
NoSuchMethodException所调用的方法未找到,引起异常
Illega1AccessExcePtion试图访问一个非public方法
StringIndexOutOfBoundsException访问字符串序号越界,引起异常
ArrayIdexOutOfBoundsException访问数组元素下标越界,引起异常
NumberFormatException字符的UTF代码数据格式有错引起异常
IllegalThreadException线程调用某个方法而所处状态不适当,引起异常
FileNotFoundException未找到指定文件引起异常
EOFException未完成输入操作即遇文件结束引起异常

42.JAVA 语言如何进行异常处理,关键字:try,catch,throw,throws,finally 分别代表什么意义?在 try 块中可以抛出异常吗?

Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和 finally。
一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;
try : 指定一块可能有“异常”的程序代码;
catch : 在 try 块后面,指定想要捕捉的“异常”的类型;
throw : 明确地抛出一个“异常”;
throws : 标明一个成员函数可能抛出的各种“异常”;
Finally : 有无异常都被执行一段代码;
在 try 块中可以抛出异常。

Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在 Java 中,每个异常都是一个对象,它是Throwable 类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可 以捕获到这个异常并进行处理。

Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和 finally。

一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally) 由缺省处理器来处理。

用 try 来指定一块预防所有"异常"的程序。紧跟在 try 程序后面,应包含一个 catch 子句来指定你想要捕捉的"异常"的类型。

throw 语句用来明确地抛出一个"异常"。

throws 用来标明一个成员函数可能抛出的各种"异常"。

Finally 为确保一段代码不管发生什么"异常"都被执行一段代码。

可以在一个成员函数调用的外面写一个 try 语句,在这个成员函数内部写另一个 try 语句保护其他代码。每当遇到一个 try 语句,"异常 "的框架就放到堆栈上面,直到所有的 try 语句都完成。如果下一级的 try 语句没有对某种"异常"进行处理,堆栈就会展开,直到遇到有 处理这种"异常"的 try 语句。

43.java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

两种方法:
① new Thread() ,继承 Thread 类 ;
② new Thread(runnable) ,实现 Runnable 接口;
用 synchronized 关键字修饰同步方法。
反对 stop(), 不安全,会解除所有锁定, 若对象是不连贯状态, 当其他线程在那种状态下检查和修改它们,很难检查出问题所在。
suspend() 方法,容易发生死锁,调用 suspend() 的时候, 目标线程会停下来, 但却仍然持有锁定。

java5 以前, 有如下两种:

  • new Thread(){}.start(); 继承 Thread 类。
    这表示调用 Thread 子类对象的 run 方法, new Thread(){}表示一个Thread 的匿名子类的实例对象, 子类加上 run 方法后的代码如下:

      		 new Thread(){
      		       public void run(){
      		     } 
      		 }.start();
    
  • new Thread(new Runnable(){}).start(); 实现 Runnable 接口。
    这表示调用 Thread 对象接受的 Runnable 对象的 run方法, new Runnable(){}表示一个 Runnable 的匿名子类的实例对象,runnable 的子类加上 run 方法后的代码如下:

      		 new Thread(new Runnable(){
      		         public void run(){
      		         } 
      		     }
      		  ).start();        
    

从 java5 开始, 还有如下一些线程池创建多线程的方式:

			  ExecutorService pool = Executors.newFixedThreadPool(3)
			  for(int i=0;i<10;i++){
			      pool.execute(new Runable(){
			          public void run(){
			          }
			      });
			  }
			  Executors.newCachedThreadPool().execute(new Runable(){
			      public void run(){
			     }
			 });
			 Executors.newSingleThreadExecutor().execute(new Runable(
			     {public void run(){
			     }
			 });             

用 synchronized 关键字修饰同步方法。

反对使用 stop(), 是因为它不安全。
它会解除由线程获取的所有锁定, 而且如果对象处于一种不连贯状态, 那么其他线程能在那种状态下检查和修改它们,结果很难检查出真正的问题所在。

suspend()方法容易发生死锁。
调用 suspend()的时候, 目标线程会停下来, 但却仍然持有在这之前获得的锁定。 此时, 其他任何线程都不能访问锁定的资源, 除非被"挂起"的线程恢复运行。
对任何线程来说, 如果它们想恢复目标线程, 同时又试图使用任何一个锁定的资源, 就会造成死锁。 所以不应该使用 suspend(), 而应在自己的 Thread 类中置入一个标志, 指出线程应该活动还是挂起。
若标志指出线程应该挂起, 便用 wait()命其进入等待状态。 若标志指出线程应当恢复, 则用一个 notify()重新启动线程

44.sleep() 和 wait() 有什么区别?

sleep 是线程类(Thread)的方法,主动让出cpu,不会释放对象锁。
wait 是 Object 类的方法,会释放对象锁,进入等待锁定池,只有针对此对象发出 notify 方法(或 notifyAll)后本线程才进入对象锁定池,准备获得对象锁进入运行状态。

sleep 就是正在执行的线程主动让出 cpu,cpu 去执行其他线程,在 sleep 指定的时间过后,cpu 才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep 方法并不会释放锁,即使当前线程使用 sleep 方法让出了 cpu,但其他被同步锁挡住了的线程也无法得到执行。

wait 是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了 notify 方法(notify 并不释放锁,只是告诉调用过 wait 方法的线程可以去参与获得锁的竞争了,但不是马上 得到锁,因为锁还在别人手里,别人还没释放。如果 notify 方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在 notfiy 方法后增加一个等待和一些代码,看看效果!),调用 wait 方法的线程就会解除 wait 状态和程序可以再次得到锁后继续向下运行。

45.同步和异步有何异同,在什么情况下分别使用他们?举例说明。

指发送一个请求,同步需要等待,异步不需要等待。

Java中交互方式分为同步和异步两种:

同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;

异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。

区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。

同步:
银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作,其余情况都优先使用异步交互。
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。

异步:
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。

46.当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对象的其它方法?

可进入非同步方法,
如果该对象的 synchronized 方法内部调用了 wait 方法,则可进入其它 synchronized 方法。

几种情况:

  1. 方法前是否加了 synchronized 关键字,如果没加,则能。
  2. 如果这个方法内部调用了 wait,则可以进入其他 synchronized 方法。
  3. 如果其他个方法都加了 synchronized 关键字,并且内部没有调用 wait,则不能。

47.多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法:继承Thread类、实现Runnable接口
同步的实现方面有两种:synchronized,wait、notify

java实现多线程有两种方法

1、继承Thread类

2、实现Runnable接口

这两种方法的共同点:不论用哪种方法,都必须用Thread(如果是Thead子类就用它本身)产生线程,然后再调用start()方法。

两种方法的不同点:

1、继承Thread类是单继承,而实现Runnable接口可多继承

2、继承Thread类若要产生Runnable实例对象,就必须产生多个Runnable实例对象,然后再用Thread产生多个线程;
实现Runnable接口,只需要建立一个实现这个类的实例,然后用这一个实例对象产生多个线程,即实现了资源的共享性。

wait() : 使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep() : 使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify() : 唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity() : 唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

48.启动一个线程是用 run()还是 start()?

启动一个线程是调用 start() 方法,run()方法 是执行代码。

启动一个线程是调用 start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法 是该线程所关联的执行代码。

49.线程的基本概念、线程的基本状态以及状态之间的关系

线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。
Java中的线程的状态:就绪,运行,synchronize 阻塞,wait和sleep挂起,结束。
调用 start 方法,线程进入就绪状态,
线程调度系统将之转为运行状态,
遇到 synchronized 时转为阻塞,
当 synchronized 获得锁后重新转为运行,
这时可调用 wait 方法(wait 必须在 synchronized 内部调用)转为挂起状态,
当线程所关联的代码执行完后,线程结束。

线程:是进程中的一个执行控制单元,执行路径一个进程中至少有一个线程在负责控制程序的执行一个进程中如果只有一个执行路径,这个程序称为单线程,一个进程中有多个执行路径时,这个程序成为多线程。
一个线程是进程的一个顺序执行流。同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多个线程。

在JVM内存模型中,线程开辟在栈中,有些前辈称之为方法的栈帧,对于这个栈帧空间就是一个线程空间,也就是一个进程调用了一个方法,这个方法在栈中就开辟一个空间,也可以认为是线程的空间,当该方法结束后,该线程就结束,但进程还在继续执行,还会继续执行接下来的方法,继续开辟线程。

线程与进程区别:
一个进程有一个或多个线程。线程更细化于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。

线程状态:

  1. 新建

    new语句创建的线程对象处于新建状态,此时它和其他java对象一样,仅被分配了内存。

  2. 等待

    当线程在new之后,并且在调用start方法前,线程处于等待状态。

  3. 就绪

    当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态。
    处于这个状态的线程位于Java虚拟机的可运行池中,等待cpu的使用权。

  4. 运行状态

    处于这个状态的线程占用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。

    只有处于就绪状态的线程才有机会转到运行状态。

  5. 阻塞状态

    阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才会有机会获得运行状态。

    阻塞状态分为三种:

    1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

    2、同步阻塞:运行的线程在获取对象同步锁时,若该同步锁被别的线程占用,则JVM会把线程放入锁池中。

    3、其他阻塞:运行的线程执行Sleep()方法,或者发出I/O请求时,JVM会把线程设为阻塞状态。当Sleep()状态超时、或者I/O处理完毕时,线程重新转入就绪状态。

  6. 死亡状态

    当线程执行完run()方法中的代码,或者遇到了未捕获的异常,就会退出run()方法,此时就进入死亡状态,该线程结束生命周期。

一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即 main 方法执行的那个线程。如果只是一个 cpu,它怎么能够同时执行多段程序呢? 这是从宏观上来看的,cpu 一会执行 a 线索,一会执行 b 线索,切换时间很快,给人的感觉是 a,b 在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网线一会为 a 传数据,一会为 b 传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。

50.简述 synchronized 和 java.util.concurrent.locks.Lock 的异同 ?

相同:Lock 能完成 synchronized 所实现的所有功能。
不同:Lock 有比 synchronized 更精确的线程语义和更好的性能。
synchronized 会自动释放锁,Lock 必须在 finally 中手工释放。
Lock 功能更强大,例如,它的 tryLock 方法可以非阻塞方式去拿锁。

主要相同点:Lock能完成synchronized所实现的所有功能。
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。
syncronized会自动释放锁,而Lock一定要程序员手动释放,并且必须在finally从句中释放。
Lock还有更强大的功能,例如它的tryLock()方法可以以非阻塞方式去拿锁。

	synchronized (lockObject) {   
	  // update object state  
	}   
	Lock lock = new ReentrantLock();  //java.util.concurrent.locks.ReentrantLock为Lock的实现类
	lock.lock(); 
	try { 
	// update object state  
	} finally { 
	  lock.unlock(); 
	} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值