线程常见面试题汇总

来源:互联网 发布:淘宝女装摄影技巧 编辑:程序博客网 时间:2024/05/02 06:09

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

程序 是计算机指令的集合它,以文件的形式存储在磁盘上。
进程是一个程序在其 自身的地址空间中的一次执行活动。
进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占系统的运行资源。
线程:进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。
线程又称轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
系统会为每个线程分配一个时间片。
在java中每个线程都 有一个优先级。
java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪个线程在CPU上运行。
在java中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程),但实际上只有一个线程在运行。该线程一直运行到它终止进入等待状态,或者另一个具有更高优先级的线程变成可运行状态。在后一种情况下,低优先级的线程被高优先级的线程抢占,高优先级的线程获得运行的机会。
java线程调度器支持不同优先级线程的抢占方式,但其本身不支持相同优先级线程的时间片轮换。
java运行时系统所在的操作系统支持时间片的轮换,则线程调度器就支持相同优先级线程的时间片轮换。

 

二 实现线程同步的方法有哪些?

线程同步指的是当一个线程占有某一公共资源时,保证其他线程不再占有该资源。

实现同步的方式有两种,一种是利用同步代码块来实现同步,如下所示:

synchronized(Object)
{
//共享资源的 关键代码
}

一种是利用同步方法来实现同步,如下所示:

public synchronized void sale()   // 同步方法中的代码为关键代码
{
   ...............

}

 

三  什么是死锁

由于两个或多个线程都无法得到相应的锁而造成的所有线程都处于等待锁的状态的现象

 

四 如何实现线程间的通信

可以通过3个方法来解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。其中,调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。而调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。需要注意的是:由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。另外,只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。

 

多线程有几种实现方法?

多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
利用继承Thread类创建的多个线程,虽然执行的是相同的代码,但彼此相互独立,且各自拥有自己的资源,互不干扰。而通过实现Runnable接口可以使多个线程拥有同一资源。所以一般在定义资源对象时实现Runnable接口。实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。

 

六 线程的基本状态和各个状态间的转化

 线程有四个状态:新建、可运行、运行、阻塞/等待/睡眠、死亡。

创建线程对象(新建)-->调用start(可运行)-->运行状态-->(1)调用wait方法(等待),(2)调用sleep方法(睡眠),(3)IO阻塞(阻塞状态)。-->运行状态-->run完成(死亡)

 

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

启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。

 

八 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。

本题其实是考查线程的同步问题,实现同步的方法有二:同步代码块和同步方法,此处代码以同步方法为例:

public class SychronizeExample {

 public static void main(String[] args){
  
  Data data = new Data();
  AddThread addThread1 = new AddThread(data);
  AddThread addThread2 = new AddThread(data);
  ReduceThread reduceThread1 = new ReduceThread(data);
  ReduceThread reduceThread2 = new ReduceThread(data);
  
  addThread1.start();
  addThread2.start();
  reduceThread1.start();
  reduceThread2.start();
  
  
 }
}
//将数据进行了封装,从而使线程、代码和数据资源三者有效分离
class Data implements Runnable{
 
 
 public void run() {
  // TODO Auto-generated method stub
  
 }
 private int j=0;
 
 public synchronized  void addJ(){
  
  System.out.println(Thread.currentThread().getName()+",加一:"+(++j));  
  
 }
 public synchronized void reduceJ(){

 
  System.out.println(Thread.currentThread().getName()+",减一:"+(--j));
  
 }
}
//用来实现加一功能的线程类
class AddThread extends Thread{
 
 private Data data;
 public AddThread(Data data){
  
  this.data = data;
 }
 @Override
 public void run() {
  // TODO Auto-generated method stub
  super.run();
  while(true){
   
   try {
    Thread.sleep(3000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   data.addJ();
  }
 }
 
}
//用来实现减一功能的线程类
class ReduceThread extends Thread{
 
 private Data data;
 public ReduceThread(Data data){
  
  this.data = data;
 }
 @Override
 public void run() {
  // TODO Auto-generated method stub
  super.run();
  while(true){
   
   try {
    Thread.sleep(3000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   data.reduceJ();
  }
 }
}

 

九 sleep()和wait()方法在线程处理中作用是一样的吗?

与sleep()不同,在wait()期间对象锁是释放的,可以通过notify()、notifyAll()或者令时间到期,从wait()中恢复执行,而且wait()方法必须在同步控制区域内调用。

原创粉丝点击