多线程测试题(附答案)

								**多线程**

一、判断题(T为正确,F为错误),每题1分
1.如果线程死亡,它便不能运行。( T )
2.在Java中,高优先级的可运行线程会抢占低优先级线程。( T )
3.线程可以用yield方法使低优先级的线程运行。( F )
yield方法:暂停线程,暂停当前正在执行的线程对象。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
yield()只能使同优先级或更高优先级的线程有执行的机会。
4.程序开发者必须创建一个线程去管理内存的分配。( T )
5.一个线程在调用它的start方法之前,该线程将一直处于出生期( T )
线程的状态:新建、可运行、运行、阻塞、死亡;
6.当调用一个正在进行线程的stop( )方法时,该线程便会进入休眠状态。( F )

7.一个线程可以调用yield方法使其他线程有机会运行。( T )
8. 多线程没有安全问题( F )
9. 多线程安全问题的解决方案可以使用Lock提供的具体的锁对象操作( T )
10. stop()方法是终止当前线程的一种状态( T )

二、选择题(不定项选择题),每题2分
1.Java语言中提供了一个( D )线程,自动回收动态分配的内存。D
A.异步 B.消费者 C.守护 D.垃圾收集
2.Java语言避免了大多数的( C )是错误的。
A.数组下标越界 B.算术溢出 C.内存泄露 D.非法的方法参数
3.有三种原因可以导致线程不能运行,它们是(ABC)
A.等待 B.阻塞 C.休眠 D.挂起及由于I/O操作而阻塞
4.当(A)方法终止时,能使线程进入死亡状态。A
A.run B.setPrority//更改线程优先级
C.sleep//线程休眠 D.yield//暂停当前线程的执行,执行其他线程
5.用(B)方法可以改变线程的优先级。B
A.run B.setPrority C.yield D.sleep
6.线程通过(C)方法可以使具有相同优先级线程获得处理器。C
A.run B.setPrority C.yield D.sleep
7.线程通过▁▁方法可以休眠一段时间,然后恢复运行。D
A.run B.setPrority C.yield D.sleep
8.方法resume( )负责重新开始▁▁线程的执行。D
A.被stop( )方法停止 B.被sleep( )方法停止
C.被wait( )方法停止 D.被suspend( )方法停止
9.▁▁方法可以用来暂时停止当前线程的运行。A
A.stop( ) B.sleep( ) C.wait( ) D.suspend( )
10. 请问下列哪些类是定义在java.io包中的抽象类(A B D)
A. InputStream B. OutputStream C. PrintStream
D. Reader E. FileInputStream F. FileWriter
三、简述题,每题5分
1、简述程序、进程和线程之间的关系?什么是多线程程序?
程序:程序就是一段代码,一组指令的集合,不能单独运行,需要将其加载到内存中,系统为他分配资源后才能执行(,运行时就相当于一个进程。静态的实体)
进程:进程就是系统分配资源调用的一个独立单位。是程序的一次动态执行,从加载到执行到执行完毕是一个完整的过程,并且有自己的生命周期。(动态的实体)
线程:线程依赖于进程存在,一个线程相当于进程的某个任务。
多线程程序:一个程序运行时(进程)产生了不止一个线程,执行的路径有多条,就叫多线程
2、什么是线程调度?Java的线程调度采用什么策略?
线程调度:对处于可运行状态的多个线程对象进行系统级的协调,防止多个线程争用有限资源而导致系统死机或者崩溃
java的线程调度采用的策略:java 的调度策略是基于线程优先级的抢先式调度。意思就是,谁的优先级高那我就先给谁使用系统资源。
3、如何在Java程序中实现多线程?
Java中实现多线程有三种方式,
1)定义一个类继承自Thread类,重写run方法,然后创建这个类的对象,然后通过对象调用start方法启动线程。
2)定义一个类实现Runnable接口,重写run方法,然后创建一个这个类的子类对象,然后建Thread类的对象,将子类对象作为参数进行传递,然后通过start方法启动线程。
3)线程池,使用ExecutorService、Callable、Future实现有返回结果的多线程。
4)JDK5以后新增了一个Executors工厂类来产生线程池,利用工厂类调用newFixedThreadPool方法,创建一个线程池对象,然后用线程池对象调用submit方法,传入的参数是一个实现了Callable接口的子类,重写了里面的call方法,submit方法相当于start方法,是用于启动线程的。
4、试简述Thread类的子类或实现Runnable接口两种方法的异同?
(1)继承Thread类,实现步骤
1)自定义一个类,继承自Thread类,然后重写里面的run方法
2)在主线程中创建自定义类的实例对象,通过调用start方法启动线程
(2)实现Runnable接口,步骤
1)自定义一个类实现Runnable接口并重写里面的run方法
2)在主线程中创建此类的实例对象
3)创建Thread类的实例对象,将自定义类的实例对象作为参数进行传递
4)通过start方法启动线程
这两个方法的共同点就是子类重写run方法,但是继承是重写Thread中的run方法,实现接口是Runnable中的run方法。而且都需要start来启动线程,是通过其创建的子类对象来调用的,接口是将子类对象作为参数来传递给Thread,然后通过Thread的对象来调用start启动的。
5、说明缓冲流的优点和原理
缓冲流的优点提高了效率,把要操作的数据放进缓冲区,然后一次性把缓冲区的内容写到目的地,而不是写一次就往目的地写一次.
缓冲流原理:缓冲区就是内存里的一块区域,把数据先存内存里,然后一次性写入,类似数据库的批量操作,这样效率比较高。
6、在Java中wait()和sleep()方法的不同?
区别1:wait方法是在Object类中,而sleep方法是Thread类中
区别2:sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。
7、Java中Runnable和Callable有什么不同?
在实现多线程时,两种不同的方法分别用到了这两种接口,当实现Runnable接口时,重写里面的run方法拥有给虚拟机调用,在实现Callable时,重写里面的call方法用于虚拟机调用,在主线程中启动时,Runable接口是通过将其子类对象传入Thread类,然后通过Thread类的对象调用start方法实现的。而Callable接口是通过线程池对象调用submit方法启动的,然后虚拟机调用call方法实现的。其中call方法可以有返回值,run方法没有。call() 可以抛出受检查的异常,比如ClassNotFoundException, 而run()不能抛出受检查的异常。
四、程序设计题
1.编写一个应用程序,在线程同步的情况下来实现“生产者―消费者”问题。
/**

  • 共享资源:

*/
package first;
public class Student {
private int age;
private String name;
private boolean flag;
public synchronized void set(String name, int age) {
if (this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
this.age = age;
this.flag = true;
this.notify();
}
public synchronized void get() {
if (!this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.name + “—” + this.age);
this.flag = false;
this.notify();
}
}

/**

  • 生产者:

/
package first;
public class Set implements Runnable {
private Student s;
public Set(Student s) {
this.s = s;
}
private int x = 0;
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
s.set(“小明”, 25);
} else {
s.set(“小华”, 27);
}
x++;
}
}
}
/
*

  • 消费者:

*/
package first;
public class Get implements Runnable {
private Student s;
public Get(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
s.get();
}
}
}

/**

  • 主线程:

/
package first;
public class First {
public static void main(String[] args) {
Student s = new Student();
Get get = new Get(s);
Set set = new Set(s);
Thread th1 = new Thread(get);
Thread th2 = new Thread(set);
th1.start();
th2.start();
}
}
2.修改上题,由于各个线程是异步运行的,因此无法预计其相对速度,为了使生产者能够不断地生产,可以使用循环缓冲区,保证有足够多的内存区保存更多的产品。(生产者——仓库——消费者)
/
*

  • 共享资源:

/
package two;
public class Student {
private int age;
private String name;
public Student() {
super();
}
public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}
public String toString() {
return “(年龄” + age + " 姓名" + name + “)”;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/
*

  • 生产者:

/
package two;
public class Producer implements Runnable {
private Box box;
public Producer(Box box) {
this.box = box;
}
@Override
public void run() {
Student student = new Student(27, “小明”);
box.push(student);
}
}
/
*

  • 消费者:

*/
package two;

public class Consumer implements Runnable {
private Box box;
public Consumer(Box box) {
this.box = box;
}
@Override
public void run() {
box.pop();
}
}
/**

  • 仓库
    /
    package two;
    public class Box {
    private Student[] students = new Student[10];
    private int top = 0;
    public synchronized void push(Student student) {
    while (top == students.length) {
    try {
    wait();// 仓库已满,等待
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    // 把产品放入仓库
    students[top++] = student;
    System.out.println(student);
    notifyAll();// 唤醒等待线程
    }
    // 消费者从仓库中取出产品
    public synchronized Student pop() {
    while (top == 0) {
    try {
    wait();// 仓库空,等待
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    // 从仓库中取产品
    –top;
    Student p = new Student(students[top].getAge(), students[top].getName());
    students[top] = null;
    System.out.println§;
    notifyAll();// 唤醒等待线程
    return p;
    }
    }
    /
    *
  • 主线程:

/
package two;
public class FirstUpgrade {
public static void main(String[] args) {
Box box = new Box();
Thread consumer = new Thread(new Consumer(box));
consumer.setName(“消费者”);
Thread producer = new Thread(new Producer(box));
producer.setName(“生产者”);
consumer.start();
producer.start();
}
}
3 、1)将若干个Student对象;若干个Teacher对象,写出到d:/0404/a.txt中,
2)将该文件中所有的Student对象反序列化回来,装入List,所有的Teacher对象反序列化回来装入另一个List
代码1)2)分别用两个方法实现:
/
*
*主线程:
*/
package three;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
write();
read();
}
private static void read() throws IOException, FileNotFoundException, ClassNotFoundException {
ObjectInputStream r1 = new ObjectInputStream(new FileInputStream(“e:\0404\a.txt”));
List list1 = new ArrayList();
List list2 = new ArrayList();
Student l1 = (Student) r1.readObject();
list1.add(l1);
Student l2 = (Student) r1.readObject();
list1.add(l2);
Teacher l3 = (Teacher) r1.readObject();
list2.add(l3);
Teacher l4 = (Teacher) r1.readObject();
list2.add(l4);
r1.close();
for (Student k : list1) {
System.out.println(k);
}
for (Teacher k1 : list2) {
System.out.println(k1);
}
}
private static void write()
throws IOException, FileNotFoundException {
ObjectOutputStream w1 = new ObjectOutputStream(
new FileOutputStream(“e:\0404\a.txt”));
Student s1 = new Student(25, “小明”);
Student s2 = new Student(24, “小华”);
Teacher t1 = new Teacher(“狂华”, “012352”);
Teacher t2 = new Teacher(“叶秋”, “012467”);

	w1.writeObject(s1);
	w1.writeObject(s2);
	w1.writeObject(t1);
	w1.writeObject(t2);
	w1.close();
}

}
/**

  • 学生类:

/
package three;
import java.io.Serializable;
public class Student implements Serializable {
/
*
*
/
private static final long serialVersionUID = 1L;
private int age;;
private String name;
public Student() {
super();
}
public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return “Student [age=” + age + “, name=” + name + “]”;
}
}
/
*

  • 老师类:
    */
    package three;
    import java.io.Serializable;
    public class Teacher implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private String number;
    public Teacher() {
    super();
    }
    public Teacher(String name, String number) {
    super();
    this.name = name;
    this.number = number;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public String getNumber() {
    return number;
    }
    public void setNumber(String number) {
    this.number = number;
    }
    @Override
    public String toString() {
    return “Teacher [name=”+name+ “, number=”+number+"]";
    }
    }

4:实现字符串和字节数组之间的相互转换,比如:将字符串“Java从入门到入土”转换为字节数组,并将字节数组再转换回字符串!
package four;
public class Four {
public static void main(String[] args) {
String s = “Java从入门到入土”;
byte[] bys = s.getBytes();
for (byte i : bys) {
System.out.print(i);
System.out.print(" ");
}
System.out.println();
String s2 = new String(bys);
System.out.println(s2);
}
}

5:用Java编程一个会导致死锁的程序,你将怎么解决?请你设计
package five;
/**
*主程
*
*/
public class Five {
public static void main(String[] args) {
// 创建线程类对象
DieLock dl1 = new DieLock();
DieLock dl2 = new DieLock();

	// 启动线程
	dl1.start();
	dl2.start();
}

}
/**

  • 解决A、B死锁:

*/
package five;
public class DieLock extends Thread {
private boolean flag = true;
public void run() {
// dl1,dl2线程
if (flag) {
synchronized (MyLock.objA) {// 锁A
System.out.println(“if objA”);
synchronized (MyLock.objB) {
System.out.println(“if objB”);
flag = false;
}
} // 代码执行完毕,objA锁相当于才能被释放掉
}
if (!flag) {
// dl2
synchronized (MyLock.objB) {// 锁B
System.out.println(“else objB”);
synchronized (MyLock.objA) {
System.out.println(“else objA”);
flag = true;
}
}
}
}
}
package five;

public class MyLock {
public static final Object objA = new Object();
public static final Object objB = new Object();

}

6:递归实现输入任意目录,列出文件以及文件夹
public class Six {
public static void main(String[] args) throws ParseException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println(“请输入目录:”);
File srcFolder = new File(br.readLine());
OutputFolder(srcFolder);
}
private static void OutputFolder(File srcFolder) {
// 获取当前srcFolder下面的所有的文件以及文件夹的File数组
File[] fileArray = srcFolder.listFiles();
// 对该对象非空判断
if (fileArray != null) {
// 增强for遍历
for (File file : fileArray) {
// 继续判断file对象是否是文件夹
if (file.isDirectory()) {
// 继续回到目录
OutputFolder(file);
} else {
// 不是目录,是文件,输出
System.out.println(file.getName());
}
}
System.out.println(srcFolder.getName());
}
}
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 面试中经常会问到线程和进程的区别。进程是指一个运行中的程序,它在计算机中拥有独立的内存空间和系统资源,可以进行通信、同步和竞争,并在某些情况下可能出现死锁。而线程是进程中的执行上下文或执行序列,它是为了实现在CPU上同时执行多个任务而引入的概念。与进程不同的是,线程共享进程的内存空间,可以方便地进行通信。\[3\]进程与线程的区别还可以从内存结构、通信方式等方面进行深入探讨。进程与进程之间不能共享内存,而线程可以共享进程的内存空间。进程之间的通信相对不方便,而线程之间的通信更加方便。进程之间的通信方式包括管道、消息队列、共享内存等,而线程之间的通信可以直接通过共享内存进行。不同的通信方式有各自的优劣点,需要根据具体的场景来选择合适的方式。\[2\]了解这些内容可以帮助你更好地回答面试中关于线程和进程的区别的问题。 #### 引用[.reference_title] - *1* *2* *3* [面试高频题:线程与进程的区别](https://blog.csdn.net/J_avaSmallWhite/article/details/111320085)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值