java工程师最新面试题(线程部分)

一般来说,把正在计算机中执行的程序叫做“进程”,所谓的“线程”是指“进程”中某个单一顺序的控制流。

要求读者掌握

1掌握java多线程机制

2.直到进程和线程的区别

3.掌握进程的几种状态

4.掌握使用两种方式创建进程

5.掌握线程的同步

6掌握线程不同状态之间的转化

Q 请说明进程好线程的区别

值得注意的是进程是属操作系统的

a一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程,使用多线程程序的并发性高

b进程在执行过程中拥有独立的内存单元,而多个线程共享内容,从而极大地提高了程序的执行效率

c.线程在执行过程中与进程还是有区别的,每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中。

D.从逻辑角度上看,多线程的意义在于一个应用程序中可有有多个执行部分可以同时执行。操作系统并没有将多个线程看作是多个独立的应用,来实现程序的调度和管理,以及资源分配。这就是进程和线程的主要区别

E.线程是具有独立功能的程序关于某个数据集合上一次运动活动,进程是系统进行资源分配和调度的一个独立的单位

F.线程是进程的一个实体,是cpu调度和分派的基本单位,他是比进程更小的独立运行的基本单位。县城本身基本上不拥有资源,只拥有一点在运行中必不可少的资源(栈,程序计数器,一组寄存器),但是它可与同属于一个进程的其他线程共享进程所拥有的全部资源

G一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

最主要的区别是  它们是不同于操作系统资源管理方式

进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的栈堆和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个程序死掉,所以多进程的程序要比多线程程序健壮,但是进程切换是,消耗资源较大,效率要差一些。

但是对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

Q一个具有生命的线程有哪些状态

创建、就绪、运行、阻塞、死亡五中状态

1创建  实例化Thread对象,但没有调用start((方法时的状态

ThreadTest a=new ThreadTest();或者Thread aa=new Thread(a);

虽然创建了Thread对象但是还是不能通过isAlive()

2就绪线程有资格运行,但调度进程还没有把它选为运行线程时所处的状态

线程创建后,调用了start方法,线程处于运行状态,但能通过isaliver方法

3运行  从就绪池中被选为但前执行的线程所处的状态

4等待、阻塞或者睡眠

线程依然活着,但是缺少条件,一旦具备条件就转化为就绪状态

Suspend方法和stop方法已经被废弃了,比较危险

5死亡一个线程run方法运行结束,那么该线程完成使命,他的栈结构将解散,也就是死完了。但他任然是一个Thread对象,仍然可以被调用,这一点与其他对象一样,而且别引用的对象也不会被垃圾回收器回收

一旦线程死去,永远不能从新启动了,也就是说不能再使用start方法让它运行

Q3那个方法是正确启动新线程。

B创建线程对象并且调用start方法

对于start方法的调用会立即返回,而线程会异步启动run方法

Q4如何创建启动线程

1继承java。Lang。Thread类

Calss ThreadTest extends Thread {
Public static void main(String[] args){
Thread t=new Thread();
t.start();
t.run(“nihao”);
}
Public void run(String name){
System.out.println(“string in run is…”);
}
Public void run(){
System.out.println(“something run here!”);
}
}
Output
String int…
Something run here

一旦调用start方法,必须给jvm留足时间,让它配置进程,而在jvm配置完成前,重载的run(string)方法被调用了,结果反而先输出 string in..然后 线程配置完成后 子啊输出 something

验证,如果在t.start加上for循环,给足充足时间,run方法就能执行

注意:这种输出结果顺序是没有保障的!不要依赖循环耗时!

Thread类中有许多管理线程的方法,包括创建、启动和暂停,所有的操作都是从run方法开始,并且在run方法内编写需要在独立线程内执行的代码。Run方法可以调用其它方法,但是执行的线程总是通过调用run方法

没有参数的run方法时自动被调用的,而带参数的run方法是被重载的,必须显示调用。

2实现java。Lang。Runnable接口

Class Thread implments Runnable{
Public void run(){
System.out.println(“something run here”);
}
..Main()
{
ThreadTest tt =new ThreadTest();
Thread t1=new Thread(tt);
Thread t2=new Thread (tt);
T1.start();
T2.start();
}
}

这种方式把线程相关的代码和线程要执行的代码分离开来。

另一种是参数式匿名内部类,

Class ThreadTest{
…Main(){
Thread t=new Thread(\new Runnable(){
Public void run(){
System.out.println(“anonymous thread”);
}
}

);
t.start();
}
}

线程的启动要调用start方法,只有这样才能创建新的调用栈。而直接调用run方法的话,就不会创建新的调用栈,也不会创建新的线程,run方法就与普通的方法没设么两样

Q5选择正确的线程说法

下面哪种说法正确?

A thread类是抽象类

B Thread类实现Runnable

C实现Runnable接口的类必须定义一个start方法

D 实现Runnable 的对象调用run方法将创建一个新的线程

E 当最后一个非守护线程结束时,程序将结束

Thread类实现了Runnable接口,不是抽象类

当最后一个非后台线程结束时,程序也就终止了

Runnable接口有一个run方法,不过该接口没有规定必须定义一个start方法

在一个runnable对象上调用run方法无法创建新的线程

Run是线程的执行方法

必须创建Thread类的实例,以生成大量的新的线程

Q6 选择正确的输出结果

package 练习;

import java.util.Scanner;

public class x extends Thread{ 

	public void run(){
	try{
		for(int i=1;i<5;i++){
		System.out.println(i+" ");
		if(i>2){
			interrupt();
		sleep(1000);
		if(interrupted())
			break;
		}
	    }
	}catch(InterruptedException e){
		System.out.println(" caugth");
	}
}
	public static void main(String[] args) {
x x=new X();
x.start();

}
Output
1
2
3
 Caught

注释: interrupt()只是改变中断状态而已. interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,给受阻塞的线程抛出一个中断信号,

这样受阻线程就得以退出阻塞的状态。更确切 的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,    那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。

如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到InterruptedException异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。

线程A在执行sleep,wait,join时,线程B调用线程A的interrupt方法,的确这一个时候A会有InterruptedException 异常抛出来.

但这其实是在sleep,wait,join这些方法内部会不断检查中断状态的值,而自己抛出的InterruptedException。

如果线程A正在执行一些指定的操作时如赋值,for,while,if,调用方法等,都不会去检查中断状态

,所以线程A不会抛出 InterruptedException,而会一直执行着自己的操作.

当线程A终于执行到wait(),sleep(),join()时,才马上会抛出 InterruptedException.

若没有调用sleep(),wait(),join()这些方法,即没有在线程里自己检查中断状态自己抛出InterruptedException的 话,

那InterruptedException是不会被抛出来的.

具体使用见实例1,实例2。

注意1:当线程A执行到wait(),sleep(),join()时,抛出InterruptedException后,中断状态已经被系统复位了,

线程A调用Thread.interrupted()返回的是false

Q7如何理解线程同步

package 练习;

import java.util.Scanner;

public class x {
	static Thread makeThread(final String id,boolean daemon){
		Thread t=new Thread(id){
		public void run(){
			System.out.println(id);
		}
	};
	t.setDaemon(daemon);
	t.start();
	return t;
	}
public static void main(String[] args) {
	Thread a=makeThread("A", false);
	Thread b=makeThread("b", true);
	System.out.println("END/");
}
}

Outout
END/
A

线程共享了相同的资源

1共享变量

要是多个线程在一个程序中有用,必须有某种方法实现线程间互相通信或者共享结果,最简单的方法是使用共享变量。使用同步来确保值从一个线程正确传播到另一个线程,以及防止当一个线程正在更新一些相关的数据项时,另一个线程看到不一致的中间结果。

2.存在某一个内容空间中的所有线程

线程与进程有许多共同点,不同的是线程与同一进程中的其他线程共享相同的进程上下文,包括内存空间。只要访问工共享变量(静态变量或实例变量),线程就可以方便地互相交换数据,但必须确保线程一受控的方式访问共享变量,以免它们互相干扰对方的更改

3受控访问的同步

为了确保可以再线程之间手控方式共享数据,java语言提供了两个关键字,synchronized和volatile、

Synchronized有以下连个重要含义

一次只有一个线程可以执行代码的受保护部分

一个线程更改的数据对于其他线程是可见的。

若果没有同步,数据很容易就处于不一致状态。

4.确保共享数据更改的可见性

同步可以让用户确保县城看到一致的内存视图

处理器可以使用高速缓存加速对内存的访问(或者编译器可以将值存储到寄存器中,以便进行更快的访问)。这表示在这样的系统上,对于同一变量,在两个不同处理器上执行的连个线程可能会看到连个不同的值。

Volatile 比同步更简单,只适合于控制对基本变量(整数、布尔变量等)单个实例的访问。当一个变量被声明为volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主存,而任何对该变量的读取也都绕过高速缓存,直接取自动主存。这表示是所有县城在任何时候看到的volatile变量值都相同。

5用锁保护的原子代码块

Volatile 对于确保每个线程看到最新的变量值非常有用,但实际上经常需要保护代码片段,同步使用监控器或锁的概念,已协调对特定代码块的访问。

每个java都有一个相关的锁,同一时间只能有一个线程持有java锁,当线程进入synchronized,线程会阻塞并等待直到锁可用。当线程处于就绪状态时,并且获得锁后,将执行代码块,当控制退出受保护的代码块,即达到了代码块末尾或者抛出没有在synchronized块中捕获的异常时,他就会释放锁

这样,每次只有一个线程可以执行受给定监控器保护的代码块。从其他线程的角度看,该代码块可以看做是原子的,他要么全部执行,要么更本不执行

6简单的同步示例

package 练习;

import java.util.Scanner;

public class x {
	private static Object lockObject=new Object();
	private static class Thread1 extends Thread{
		int x,y;
		public void run(){
			synchronized(lockObject){
				x=y=0;
				System.out.println(x);
			}
		}
	}
	private static class Thread2 extends Thread{
		int x,y;
public void run(){
	synchronized(lockObject){
		x=y=1;
		System.out.println(x);
	}
}
	}
		public static void main(String[] args) {
		new Thread1().run();
		new Thread2().run();

	}
}

将会打印 01或者10 如果没哟同步,他还会打印11 或00

7java锁定

Java锁定可以保护许多代码块或方法,每次只有一个线程就可以持有锁,如果两个线程正在等待相同的锁,则他们不会同时执行该代码

在以下示例中,连个线程可以同时不受限制地执行setLastAccess()方法中的synchronized块,因为每个线程有一个不同的thengie值。因此synchronized代码块受到两个正在执行的线程不同锁的保护。

package 练习;

import java.util.Date;

import java.util.Scanner;

public
class
x {

public
staticclass
Thingie{

private Date
lastAccess;

public
synchronized void
setLastAccess(Date
date){

this.lastAccess=date;

}

}

public
staticclass
MyThread extendsThread{

private Thingie
thingie;

public MyThread(Thingie
thingie){

this.thingie=thingie;

}

public
void
run(){

thingie.setLastAccess(new Date());

}

}

public
static void
main(String[]
args) {

Thingiethingie=new Thingie();

Thingiethingie2=new Thingie();

new MyThread(thingie).start();

new MyThread(thingie2).start();

}

}

8同步方法

创建synchronized块的最简单方法是将方法声明成synchronized。这表示在进入方法主体前,调用者必须获得锁。

9同步的块

Synchronized块的语法比synchronized方法稍微复杂一些,因为还需要显示地指定锁要保护哪个块。

Public class point{

Public void setXY(int x,int y){

Synchronized(this){

This.x=x;

This .y=y;

}

}

使用this引用作为锁表示代码块将于这个类中的synchronized方法使用同一个锁

10大多说类并没有同步

因为同不会带来小小的性能损失

Q 线程同步选择题

运行下面例子会输出什么

package 练习;

import java.util.Date;

import java.util.Scanner;

public class X extends Thread {

staticObject lock1=new Object();

staticObject lock2=new Object();

staticvolatile int i1,i2,j1,j2,k1,k2;

publicvoid run(){

while(true){

doit();

check();

}

}

voiddoit(){

synchronized(lock1) {

i1++;

}

j1++;

synchronized(lock2) {

k1++;

k2++;

}

j2++;

synchronized(lock1) {

i2++;

}

}

voidcheck(){

if(i1!=i2){

System.out.println("i");

}

if(j1!=j2){

System.out.println("j");

}

if(k1!=k2){

System.out.println("k");

}

}

public static void main(String[] args) {

newX().start();

newX().start();

}

}

Outout

output

在执行过程中不能确定打印字母i,j,k的哪一个。

Q9下面哪些事件会导致线程死亡

A sleep()

B wait()

C Start()

D run

E线程构造执行结束

在java线程中,正在运行的线程可以转化为不可运行状态,八十线程不能够从不可运行状态直接转化为运行状态,而是首先转化为准备运行状态。

Interrupt():中断调度此方法线程。在等待通知、休眠或者阻塞以等待挂起完成的状态,线程会抛出InterruptedException异常

Yield():是线程暂时停止运行

1线程调度的优先级

Java将线程的优先级分为1个等级,分别是1-10之间的数字表示。数字越大表示等级越高。当一个线程对象被创建时,默认的线程优先级是5

为了控制现成的运行策略,java定义了线程调度器来监控系统中处于就绪状态的所有线程。线程调度器采用“抢占优先级”策略来调度线程执行。具有相同优先级的所有线程采用轮状的方式同分配cpu时间片。

使用setPriority()方法改变线程的优先级。

在Java中比较特殊的线程被称为守护线程deaemon线程的低级线程。这个线程具有最低的优先级。用于系统中的其他对象和线程提供服务。设置为一个守护线程方式是,在线程对象创建之前调用setdaemon方法。Jvm中的系统资源自动回收线程,他始终是在低级别的状态中运行。用于实施监控和管理系统中的可回收资源。

2.运行和挂起

线程通过start方法调用后,线程就进入了准备运行状态。进入准备运行阶段后,线程才能获得·运行的资格,即获得cpu的时间

系统进程调度器来决定哪个线程可以运行,并确定其运行时间,也就是说,线程具有不可预测性。

调用yield方法将会导致当前线程从运行状态转化为准备运行状态。使用yield方法的好处就是可以让出cpu的时间,供其他线程使用。

package 练习;

importjava.util.Date;

importjava.util.Scanner;

public class Xextends Thread {

public staticvoid main(String []args){

Mythread3mythread32=new Mythread3("t2");

Mythread3mythread3=new Mythread3("t1");

mythread3.start();

mythread32.start();

}

}

class Mythread3extends Thread{

publicMythread3(String s) {

// TODOAuto-generated constructor stub

super(s);

}

public voidrun(){

for(inti=0;i<100;i++){

System.out.println(getName()+":"+i);

if(i%10==0){yield();

}}}

}

t1: 0

t1: 1

t1: 2

t1: 3

t1: 4

t1: 5

t1: 6

t1: 7

t1: 8

t1: 9

t1: 10

t1: 11

t1: 12

t1: 13

t1: 14

t1: 15

t1: 16

t1: 17

t1: 18

t2: 0

t2: 1

t2: 2

t2: 3

sleep()方法

使当前线程(即调用该方法)暂停执行一段时间,让其他线程有机会继续执行,但他并不释放对象锁,也就说如果synchronized同步块,其他线程任然不嗯能够访问共享数据,注意该方法要捕获异常。

总之,sleep可以使低优先级的线程的待执行的机会,也可以让同优先级。高优先级的线程有执行的机会。

3 wait()和notify()

如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒,在java中,这个机制的实现依赖于wait和notify。等待机制和锁机制是密切关联的

Synchronize(obj){

While(!condition){

Obj.wait()

}

Obj.doSomething();

}

}

当线程A获得obj锁后,发现条件condition不满足,无法继续下一处理,于是线程a就等待(wait)

再赢一个线程b中,如果b更改了某些条件,使得线程a的condition条件满足了,就可唤醒线程A

Synchronized(obj){

Condition=true;

Obj.notify()

}

4线程调度规则

如果两个或是两个以上的线程都修改一个对象,那么把执行修改的方法定义为同步的(synchronized),如果对象更新影响到只读方法,那么只读方法也因该定义为同步的

如果一个线程必须等待一个对象状态变化,那么他应该在对象内部等待,而不是在外部等待,它可以调用一个被同步的方法,并让这个方法调用wait方法。

每当一个方法改变某个对象的状态时,它应该调用notify方法,这个等待队列的线程提供了机会,来看一看执行环境是否已经发生改变

记住wait notify notifyall 方法属于object,而不是thread类,仔细检查看看是否每次执行wait方法都有相应的notify或notifyall方法,且他们作用与相同的对象

注意:在java总每个类都有一个主线程,要执行一个程序,那么这个类当中一定要有main方法,main方法是java类中的主线程。自己创建线程有两种方法,一种是集成thread类,另一种是实现runnable接口。一般情况下,最好避免继承,因为java中是单根继承,如果继承thread类,则无法再继承其他类。

Q10 调用yield方法可以保证什么

A 所有优先级较低的线程获得cpu时间

B 当前线程休眠一段时间,其他线程运行

C 当前线程停止,直到其他线程终止

D 线程将等待,直到被通知

E以上都不正确

E  线程调度器的确切行为是没有定义的,不能保证yield方法的调用hi导致其他线程使用cpu

Q11notify方法意义在何处

A线程 b对象  c applet drunnable

b

时间: 2024-10-07 14:13:31

java工程师最新面试题(线程部分)的相关文章

【转】2012年6月26 – PPS网络电视PHP工程师最新面试题

每一次面试都是一场较量,和面试官,更是和你自己! 前言:虽然面试职位是PHP工程师,但题目仅绝非限于PHP,甚至都没有多少PHP的题!inner peace!希望能给你带了一丝帮助. PPS网络电视面试题(PHP工程师)非答案!!!请自行请教谷歌大神. 四张纸的笔试.去的比较晚,所以只剩半小时时间了!当时我就震惊了.跟同座一起来笔试的几个哥们开玩笑:尼玛这比高考还猛啊!这么多半小时! 不过其中一哥们当真进入了状态,拿出手机在百度!喂!帅哥,这么多算法题,百度有用么?待会还有口试了! 笔试略,不算

Java工程师笔试面试题集 一

一.笔试题目: 1. 简述类与对象的区别,Java 虚函数的作用. 类是对象的抽象,对象是类的具体实例.类是抽象的,不占用内存,而对象是具体的,占有内存空间. java中没有虚函数的概念,普通函数就相当于C++中的虚函数,不过可以在函数前加final使函数不能被重写.虚函数的作用是允许在派生类中重新定义与基类同名的函数,是多态性的一种体现. 2. Database table 写SQL语句去掉重复的记录,保留其中ID最小的一条. delete from tablename where id no

【转】2012年6月26 – 盛大PHP工程师最新面试题

无笔试. 口试:(前半部分平淡无奇,没什么太难的问题,都是求职岗位基本要会的东西,局限于php.下面是真正进入状态的题.) 谈谈观察者模式是什么?主要应用. 答:类似会有一些server对象时刻侦听某个对象的一些动作.被监听的对象也会有这个server列表,或者提供添加列表的接口.促发条件根据需 求.触发的时候这个object对象会发送本身给这些server列表中的一个方法里,这样server也就会取得传过来的对象实现侦听.主要应用在插件 上的. 什么是索引?建立索引有什么规则?注意点? 答:类

【转】2012年7月12 – 腾讯公司 WEB高级应用开发工程师 最新面试题

腾讯面试(WEB高级应用开发工程师<PHP>)非答案啊!!! 开始正题之前,容博主啰嗦两句吧,呵呵.(你也可跳过直接到红色字体看题!) 腾讯一直是我很敬重的企业,尽管小企鹅在战略上饱受争议,正面的,负面的我就不一一列举了,但又怎样?在中国,他还是能如微软一样,渗透到每一个用户的日常生活中去,这样的成绩,恐怕在世界范围内也没有多少吧!想进去自然困难丛丛,面试周期达一个月之久.技术面试只占四分之一,剩下的都是人品关!我勒个去!你知道技术对鄙人还算凑活,可这RP,我是一直持保留意见的!不过话说回来,

java程序员面试题大全含答案(2018--2019)

java程序员面试题大全含答案(2018--2019) 1.10道经典java面试题_实习生必问! 2.15个Java线程并发面试题和答案 3.15个高级Java多线程面试题及回答 4.2018年java分布式相关最新面试题 5.2018最新java技术面试题与答案 6.4个Spring常见面试题及答案解析 7.css面试题及答案 8.HR常问面试题总结(上) 9.HR常问面试题总结(下) 10.html面试题及答案 11.java中String类的面试题大全含答案 12.java二叉树算法面试

今日头条3面,被泄露的Java最新面试题

一.面试第 1 轮 1. linux 网络模型 2. b+树 3. 阻塞队列 4. redis 和 MongoDB 的区别.几个概念对比,还有底层实现. 5. 算法题: merge k sorted list,时间复杂度如何? 6. HashMap 如果一直 put 元素会怎么样?hashcode 全都相同如何?equals 方法都相同 如何? 7. ApplicationContext 的初始化过程?初始化过程中发现循环依赖 Spring 是如何处理的. 8. GC 用什么收集器?收集的过程如

Java开发工程师上机笔试题

网上看到3道比较好的Java开发工程师上机笔试题,没有答案这里把答案写出来,给大家参考. 1.编一个程序,输入10个整数,并放在数组中,先降序输出所有的数,再统计并输出其中正数.负数和零的个数 package cn.Pigzhu.test; import java.util.Scanner; /**  * 控制台输入10个数字,并输入正负和零的个数  * @author xiaoyezhu  *  */ public class test { public static void main(St

Java工程师笔试题整理[校招篇]

隔着两个月即将开始校招了.你是不是也想借着这个机会崭露头角,拿到某些大厂的offer,赢取白富美.走上人生巅峰?当然如果你还没能打下Java基础,一定要先打好Java基础:如何一步一步的学Java - 学习编程 - 知乎专栏.然后再来看一下练习一下各大厂的面试笔试题目. 如果以下内容满足不了你,你还可以去看这篇: 2016校招编程题汇总 - 学习编程 - 知乎专栏 进入主要内容(主要内容整理来自牛客网:牛客网)(以下内容按照各大公司进行划分,对每一公司按照年份进行划分,如果想想下载以下内容,可以

50道最新java基础部分面试题(二)

java基础部分面试题(前11题请看上一篇博客)12.静态变量和实例变量的区别? 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加.在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量.静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了.总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直