java--多线程练习题

来源:互联网 发布:java面向过程实现加法 编辑:程序博客网 时间:2024/05/17 05:16

多线程

一、判断题(T为正确,F为错误),每题1
1.如果线程死亡,它便不能运行。(T
2.Java中,高优先级的可运行线程会抢占低优先级线程。(
3.线程可以用yield方法使低优先级的线程运行。(F
4...程序开发者必须创建一个线程去管理内存的分配。(T
5.一个线程在调用它的start方法,之前,该线程将一直处于出生期。(T
6.当调用一个正在进行线程的stop( )方法时,该线程便会进入休眠状态。(F
7.一个线程可以调用yield方法使其他线程有机会运行。(T

8. 多线程没有安全问题(F)

9. 多线程安全问题的解决方案可以使用Lock提供的具体的锁对象操作(T)

10. Stop()方法是终止当前线程的一种状态(T)

 

二、选择题(不定项选择题),每题2
1.Java语言中提供了一个线程,自动回收动态分配的内存。D
A.异步
B.消费者
C.守护
D.垃圾收集
2.Java语言避免了大多数的错误。C
A.数组下标越界
B.算术溢出
C.内存泄露
D.非法的方法参数
3.有三种原因可以导致线程不能运行,它们是A B C
A.等待
B.阻塞
C.休眠
D.挂起及由于I/O操作而阻塞
4.方法终止时,能使线程进入死亡状态。A
Arun
BsetPrority//更改线程优先级
Cyield//暂停当前线程的执行  执行其他线程
Dsleep//线程休眠
5.方法可以改变线程的优先级。B
Arun
BsetPrority
Cyield
Dsleep
6.线程通过▁▁方法可以使具有相同优先级线程获得处理器。C
Arun
BsetPrority
Cyield
Dsleep
7.线程通过▁▁方法可以休眠一段时间,然后恢复运行。D
Arun
BsetPrority
Cyield
Dsleep
8.方法resume( )负责重新开始▁▁线程的执行。D
A.被stop( )方法停止
B.被sleep( )方法停止
C.被wait( )方法停止
D.被suspend( )方法停止
9.▁▁方法可以用来暂时停止当前线程的运行。A
Astop( )
Bsleep( )
Cwait( )
Dsuspend( )

10. 请问下列哪些类是定义在java.io包中的抽象类() A B D

A. InputStream

B. OutputStream

C. PrintStream

D. Reader

E. FileInputStream

F. FileWriter

 

三、简述题,每题5
1.简述程序、进程和线程之间的关系?什么是多线程程序?

程序:程序就是一段代码,一组指令的集合,不能单独运行,需要将其加载到内存中,系统为他分配资源后才能执行(,运行时就相当于一个进程。静态的实体)

进程:进程就是系统分配资源调用的一个独立单位。是程序的一次动态执行,从加载到执行到执行完毕是一个完整的过程,并且有自己的生命周期。(动态的实体)

线程:线程依赖于进程存在,一个线程相当于进程的某个任务。

多线程程序:

一个程序运行时(进程)产生了不止一个线程,执行的路径有多条,就叫多线程
3.什么是线程调度?Java线程调度采用什么策略?

线程调度:

对处于可运行状态的多个线程对象进行系统级的协调,防止多个线程争用有限资源而导致系统死机或者崩溃

java线程调度采用策略

java 的调度策略是基于线程优先级的抢先式调度。意思就是,谁的优先级高那我就先给谁使用系统资源。

4. 如何在Java程序中实现多线程?

     Java中实现多线程有三种方式,

1)定义一个类继承自Thread类,重写run方法,然后创建这个类的对象,然后通过对象调用start方法启动线程。

2)定义一个类实现Runnable接口,重写run方法,然后创建一个这个类的子类对象,然后建Thread类的对象,将子类对象作为参数进行传递,然后通过start方法启动线程。

3)线程池,使用ExecutorServiceCallableFuture实现有返回结果的多线程。

4)JDK5以后新增了一个Executors工厂类来产生线程池,利用工厂类调用newFixedThreadPool方法,创建一个线程池对象,然后用线程池对象调用submit方法,传入的参数是一个实现了Callable接口的子类,重写了里面的call方法,submit方法相当于start方法,是用于启动线程的。

5.试简述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启动的。

6. 说明缓冲流的优点和原理

缓冲流的优点提高了效率,把要操作的数据放进缓冲区,然后一次性把缓冲区的内容写到目的地,而不是写一次就往目的地写一次.

缓冲流原理:缓冲区就是内存里的一块区域,把数据先存内存里,然后一次性写入,类似数据库的批量操作,这样效率比较高。

8:Javawait()sleep()方法的不同?

区别1wait方法是在Object类中,而sleep方法是Thread类中

区别2sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

9:JavaRunnableCallable有什么不同?

.在实现多线程时,两种不同的方法分别用到了这两种接口,当实现Runnable接口时,重写里面的run方法拥有给虚拟机调用,在实现Callable时,重写里面的call方法用于虚拟机调用,在主线程中启动时,Runable接口是通过将其子类对象传入Thread类,然后通过Thread类的对象调用start方法实现的。而Callable接口是通过线程池对象调用submit方法启动的,然后虚拟机调用call方法实现的。其中call方法可以有返回值,run方法没有。call()可以抛出受检查的异常,比如ClassNotFoundException, 而run()不能抛出受检查的异常。

 

四、程序设计题
1.编写一个应用程序,在线程同步的情况下来实现生产者消费者问题。

代码:主线程:

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();

}
}

生产者:

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 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();
}
}

2.修改上题,由于各个线程是异步运行的,因此无法预计其相对速度,为了使生产者能够不断地生产,可以使用循环缓冲区,保证有足够多的内存区保存更多的产品。(生产者——仓库——消费者)

 代码:

主线程:

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();  
}
}

 生产者:

package two;


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;


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(p);  
        notifyAll();//唤醒等待线程  
        return p;  
    }  
}  

共享资源:

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;
}


}

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<Student> list1= new ArrayList<Student>();
List<Teacher> list2= new ArrayList<Teacher>();
   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:实现字符串和字节数组之间的相互转换,比如:将字符串西部开源技术中心xbkyjszx”转换为字节数组,并将字节数组再转换回字符串!

代码:

package four;


public class Four {
public static void main(String[] args) {
String s="西部开源技术中心xbkyjszx";
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() ;
}
}

 两把锁:

package five;


public class MyLock {

public static final Object objA = new Object() ;
public static final Object objB = new Object() ;

}

解决A、B死锁:

package five;


public class DieLock extends Thread{
private boolean flag=true;


//重写run()方法

@Override
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;
}
}
}

}
}

6:递归实现输入任意目录,列出文件以及文件夹

代码:

package six;


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;


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());
}
}
}