资源描述
《Java语言程序设计基础教程》练习思考题参考答案
第7章多线程
7.1单项选择题
1、Java语言具有许多优点和特点,下列选项中,哪个反映了 Java程序并行机制的特
点?()
A、安全性B、多线程
C、跨平台D、可移植
解答:B
2、Runnable接中的抽象方法是()。
A、startB、stop
C、yieldD、run
解答:D
3、有以下程序段(很难)
class MyThread extends Thread {
public static void main(String args[]) {
MyThread t = new MyThread();
MyThread s = new MyThread();
t.start();
System.out.print("one.");
s.start();
System.out.print("two.");
}
public void run() {
System.out.print("Thread");
}
}
则下面正确的选项是()
A、编译失败
B、程序运行结果为:one.Threadtwo.Thread
C、程序运行结果是:one.two.ThreaThread
D、程序运行结果不确定
解答:D
5、作为类中新线程的开始点,线程的执行是从下面哪个方法开始的。()
A、public void start()
B、public void run()
C、public void int()
D、public static void main(String args[])
解答:A
6、Java中用于给对象加“互斥锁”标记的关键字是。()
A、synchronized
B、serialize
C、transient
D、static
解答:A
7. 以下哪个方法用于定义线程的执行体?( C )
A、 start()B、init()
C、run()D、synchronized。
8. 以下哪个关键字可以用来为对象加互斥锁?( D )
A、transient B、static
C、 serialize D、 synchronized
7.2填空题
7.3简答题
1、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
多线程有两种实现方法,分别是继承Thread类与实现Runnable接。用Thread类的 子类创建线程对象,也就是从Thread类继承。实现Runnable接,用Thread类直接创建 线程对象。
同步的实现方面有两种,分别是synchronized wait与notify
2、创建一个新线程的方法,可以使用下面哪2种(
A、继承java.lang.ThreO!,并且重载run方法。
B、继承 java.lang.Runnab粪,并且重载 star方法。
C、实现java.lang.thre类d实现run方法。
D、实现 java.lang.Runnab接,实现 run方法。
E、实现 java.lang.ThreOd,实现 star方法。
解答:A,D
3、线程在它的一个完整的生命周期中有哪4种状态?
解答1:
线程在它的一个完整的生命周期中通常要经历如下的4种状态:1.创建状态(new Thread) 2.可运行状态(Runnable )不可运行状态(Not Runnabl)4.死亡状态(Dead)
解答2:
第一是创建状态。在生成线程对象,并没有调用该对象的star方法,这是线程处于创 建状态。
第二是就绪状态。当调用了线程对象的star方法之后,该线程就进入了就绪状态,但 是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之 后,从等待或者睡眠中回来之后,也会处于就绪状态。
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就 进入了运行状态,开始运行run函数当中的代码。
第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比 如说某项资源就绪)之后再继续运行。sleep,suspendwait等方法都可以导致线程阻塞。
第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就 会死亡。对于已经死亡的线程,无法再使用star方法令其进入就绪。
4、线程在什么状态时,调用isAlive方法返回的值是false
5、建立线程有哪两种方法?
解答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接。
6、怎样设置线程的优先级?
7、调用Thread类的什么方法可以启动一个线程?直接调用Thread类的run(方法可以 启动一个线程吗?
解答:线程调用start方法将启动线程,从新建状态进入就绪队列排队。不能直接调用 Thread类的run(方法可以启动一个线程,我们调用了 Thread的run(方法,它的行为就会和 普通的方法调用一样。
8、Thread类中的start (和 run ()方法有什么区别?
解答:这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。 start方法被用来启动新创建的线程,而且start内部调用了 run(方法,这和直接调用run() 方法的效果不一样。当你调用run(方法的时候,只会是在原来的线程中调用,没有新的线 程启动,start方法才会启动新线程。
9、进程和线程的区别?
解答:进程=执行中的程序,每个进程都有自己独立的一块内存、一组系统资源。每一 个进程的内部数据和状态都是完全独立的。
线程=进程中单个顺序的流控制,同类的多个线程共享一块内存、一组系统资源。线程 的运行开销很小。
一个线程是进程的一个执行流程,一个进程可以同时包含多个线程。
10、现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执 行完后执行?
解答:在T2线程的run(方法中加入代码T1.join在T3线程的run(方法中加入代码 T2.join
或者在主线程main (方法中,
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t3.start();
11、Thread.start()Thread.run有什么区别?
解答:通过调用Thead类的start方法来启动一个线程,使之进入就绪状态,当cpu 分配时间该线程时,由JVM调度执行run(方法。直接使用run(方法叫做方法调用,不能 启动线程。
12、在一个对象上两个线程可以调用两个不同的同步实例方法吗?
解答:不能,因为一个对象已经同步了实例方法,线程获取了对象的对象锁。所以只 有执行完该方法释放对象锁后才能执行其它同步方法。
13、当一个同步方法已经执行,线程能够调用对象上的非同步实例方法吗?
解答:可以,一个非同步方法总是可以被调用而不会有任何问题。实际上,Java没有 为非同步方法做任何检查,锁对象仅仅在同步方法或者同步代码块中检查。如果一个方法 没有声明为同步,即使你在使用共享数据Java照样会调用,而不会做检查是否安全,所以 在这种情况下要特别小心。一个方法是否声明为同步取决于临界区访问(critia^ction access如果方法不访问临界区共享资源或者数据结构)就没必要声明为同步的。
14、wait方法的作用?
解答:wait方法用在synchronized方法或者synchronize块中。一般在判断语句中, 如果某条件被触发,让当前线程wait并释放对象的锁。此时可以让其他线程可以对用以对 象调用synchronize方法。直到调用notif或者notifyAl后wait的线程才有可能执行。所 以一般wait和notify是成对出现的。
15、启动一个线程是用run(还是start,()调用的时候有什么区别?(同第8题)
解答:当然是start了),当调用线程的start方法的时候,线程就会进入到就绪状态。 run(方法是线程的执行入,当线程从就绪状态进入到执行状态时首先要从run(方法开始 执行。
当然,我们也是可以直接通过线程对象调用该对象的run(方法的,只是这只是一次普 通的调用,并没有启动任何一个线程。
当我们调用start方法时,是另外启动了一个线程去执行线程类的代码,并不影响主程 序的执行,但是调用run(方法的时候要等待run(方法内的代码执行完主程序才可以向下执 行
16、sleep(和 wait()有什么区别?
解答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会 给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait 是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等 待锁定池,只有针对此对象发出notify方法(或notifyAl)l后本线程才进入对象锁定池准备 获得对象锁进入运行状态。
7.4综合题
14、编写一个死锁程序?
15、在下面的代码区填入相应的代码,实现以下功能:
通过继承Thread类的子类Threadl,来创建和启动一个线程tl;
通过实现Runnable接的具体类Runner1,来创建和启动一个线程t2;
public class TestThread1{
public static void main(String[] args){
/创建和启动一个线程t1,在下面写出相应代码 Thread1 t1 =new Thread1 () ;
t1.start() ;
/创建和启动一个线程t2在下面写出相应代码
Runner1 r1 =new Runner1() ;
Thread t2 =new Thread(r1) ;
t2.start() ;
for(int i=0;i<1;i++){
System.out.println("Main Thread:"+ i);
}
}
}
class Runner1 implements Runnable{
public void run(){
for(int i=0;i<1;i++){
System.out.println("Runner1:"+i);
}
}
}
class Thread1 extends Thread{
public void run(){
for(int i=0;i<1;i++){
System.out.println("Thread1:"+i);
}
}
}
16、现在有T1 T2 T3三个线程,怎样保证T2在T1执行完之后执行T3在T2执行完 之后执行。请在相应区域写出实现该功能的代码。
public class JoinDemo {
public static void main(String[] args) {
T1 t1=new T1("T1");
T2 t2=new T2("T2");
T3 t3=new T3("T3");
t1.start();
try {
t1.join();
} catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace();
}
t2.start();
try {
t2.join();
} catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace();
}
t3.start();
}
}
class T1 extendThread{
private String name;
public T1(String name) { this.name=name;
}
public void run()(
for(int i=0;i<5;i++){ try {
sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
System.out.println(this.n 循环" + i);
}
class T2 extendThread{
private String name;
public T2(String name) { this.name=name;
}
public void run()(
for(int i=0;i<5;i++){ try {
sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
System.out.println(this.n 循环" + i);
}
}
}
class T3 extendThread(
private String name;
public T3(String name) { this.name=name;
}
public void run()(
for(int i=0;i<5;i++){
System.out.println(this.n 循环" + i);
}
}
}
第8章文件和流
8.1单项选择题
1、创建一个向文件“file. ”x追加内容的输出流对象的语句是()。
A. OutputStream out=new FileOutputStream("file.txt”);
B. OutputStream out=new FileOutputStream("file.txt”, “append”);
C. FileOutputStream out=new FileOutputStream("fiUe)txt”, tr
D. FileOutputStream out=new FileOutputStream(new file("file.txt”)); 解答:C
2、下面哪个流类属于面向字符的输入流()
A BufferedWriterB FileInputStream
C ObjectInputStreamD InputStreamReader
答案:D
3、以下关于File类说法错误的是(D)
A. 一个File对象代表了操作系统中的一个文件或者文件夹
B. 可以使用File对象创建和删除一个文件
C. 可以使用File对象创建和删除一个文件夹
D. 当一个File对象被垃圾回收时,系统上对应的文件或文件夹也被删除
4、为了提高读写性能,可以采用什么流? ( D )
A InputStream
B DataInputStream
C OutputStream
D BufferedInputStream
5、File类型中定义了什么方法来判断一个文件是否存在?( D )
A createNewFile
B renameTo
C delete
D exists
6、File类型中定义了什么方法来创建多级目录? ( C )
A createNewFile
B exists
C mkdirs
D mkdir
7、(Buffered流,缓冲区)有下面代码 import java.io.*;
public class TestBufferedWriter{
public static void main(String args[]) throws Exception(
FileWriter fw = new FileWriter("test.txt”);
BufferedWriter bw = new BufferedWriter(fw);
String str = “Hello World”;
bw.write(str)) }
在处放入什么代码,能够使得test.tx文件被正确写入?
A. bw.close() B. bw.flush(); C. fw.close();
8.2填空题
1、 对于FileInputStrea来说,从方向上来分,它是输入流,从数据单位上
分,它是―一字节___流。
2、创建FileOutputStreai对象时,如果对应的文件在硬盘上不存在,则会_自动创建___;
如果对应的文件在硬盘上已经存在,则―覆盖
8.3简答题
1、java中有几种类型的流? JDK为每种类型的流提供了一些抽象类以供继承,请说出 他们分别是哪些类?
解答:
字节输入流:InputStrean字节输出流:OutputStream
字符输入流:Reader,字符输出流:Writer
2、什么是java序列化,如何实现java序列化?
解答:Java对象的序列化指将一个java对象写入OI流中,与此对应的是,对象的反序 列化则从IO流中恢复该java对象。
如果要让某个对象支持序列化机制,则必须让它的类是可序列化的,为了让某个类是 可序列化的,该类必须实现Serializable或Externalizab接。
8.4综合题
3、FileInputStrea流的read方法和FileRead流的read方法有何不同?
4、BufferedReade疏能直接指向一个文件对象吗?
1、( FileInputStrea和 FileOutputStrea)n利用 FileInputStrea和 FileOutputStream 完成下面的要求:
1 )用FileOutputStrean在当前目录下创建一个文件“test.txt并向文件输出“Hello World”,如果文件已存在,则在原有文件内容后面追加。
2 )用FileInputStrea读入test.txt件,并在控制台上打印出test.tx中的内容。
3 )要求用try-catch-fina处理异常,并且关闭流应放在finally中。
FileInputStream fin;
FileOutputStream fon;
try(
fin = new FileInputStream("hello.txt");
on = new FileOutputStream("test.txt",true);
fon.write("Hello World”); System.out.println( fin.read() ); fin.close();
}catch(Exception e){}finally{fin.close();}
1、使用FileInputStrea类,编写一个程序,顺序读取d:/text.的文件里的内容,并 显示在控制台上面,直到文件结束为止。?
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ep8_2 {
public static void main(String[] args) { FileInputStream fis; try {
fis = new FileInputStream("text.txt");
System.out.print("content of text is :"); int b;
while ((b = fis.read()) 3/顺)序读取文件 textM的内容{
System.out.print((char) b);
} fis.close();
} catch (FileNotFoundException e) { System.out.println(e);
} catch (IOException e) { System.out.println(e);
}
2、使用 FileInputStre磷和 FileOutputStrea类,编写一个程序,顺序读取 d:/text.txt 的文件里的内容,并将内容拷贝到d:/text.bak件?
import java.io.*;
public class TestFileOutputStream{
public static void main(String[] args){ int b = 0 ; FileInputStream in =null ; FileOutputStream out = null; try{
in = new FileInputStream("d:/text.txt");
out = new FileOutputStream("d:/text.bak");
while((b=in.read())!=-1){ out.write(b);
}
in.close();
out.close();
}catch(FileNotFoundException e2){
System.out.print 找不到文件");System.exit(T);
}catch(IOException e1){
System.out.printtil 件复制错误");System.exit(T); } System.out.print ^文 件已经复制");
}
}
3、递归列出d:/jav目录下的所有子目录和文件,再显示到控制台 import java.io.* ;
public class FileList{
public static void main(String[] args){ File f = new File("d:/java") ; System.out.println(f.getName()) ; tree(f,1) ;
}
private static void tree(File f, int level){
for(int i=0;i<level;i++){ preStr +="";
}
File[] childs = f.listFiles();
for(int i=0 ;i<childs.length; i++){
System.out.println(preStr + childs[i].getName());
if(childs[i].isDirectory()){ tree(childs[i],level +1);
}
}
}
}
4、首先列出当前工作目录,然后将当前目录下面的所有文件取出,根据过滤器设置, 显示后缀为java的所有文件。
import java.io.*;入//java.i 包中所有的类
public class ep8_1 {
public static void main(String args[]) {
File dir = new File("c://java_work 用8F)le 对象表示一个目录
Filter filter = new Filter("j生喊一;个名为 java的过滤器
System.out.println("list java files in directory " + dir);
String files[] = dir.list (歹小毗融录dM下,文件后缀名为java的所有文件
for (int i = 0; i < files.length; i++) {
File f = new File(dir, file为[剧录d//下的文件或目录创建一个File 对象
if (f.isFile伽果该对象为后缀为java的文件,则打印文件名
System.out.println("file " + f); else
System.out.println("sub directory "如如果是目/录则打印目录名
}
}
}
class Filter implements FilenameFilter { String extent;
this.extent = extent;
public boolean accept(File dir, String name) {
return name.endsWith("." + extent)回文件的后缀名
}
}
5、请编写一个程序,开启一个文本文件,一次读取其内的一行文本,令每行形成一 个String并将读出的Strin对象置于LinkedLis中,以反相次序显示出LinkedList内的所 有内容。
import java.io.*;
import java.util.*;
class exA4_2(
public static void main(String args[]) throws Exception(
LinkedList lines=new LinkedList();
BufferedReader in=
new BufferedReader(new FileReader("exA4_2.java"));
String s;
while((s=in.readLine())!=null)
lines.add(s);
in.close();
Listiterator it=lines.listIterator(lines.size());
while(it.hasPrevious())
System.out.println(it.previous());
}
}
6、在程序中写一个"HelloJavaWorlc#好世界"输出到操作系统文件Hello.tx文件中 import java.io.File;
import java.io.FileOutputStream;
public class Test5 {
/**
*在程序中写一个"HelloJavaWorld你好世界"输出到操作系统文件Hello.tx文件 中
*
*程序分析:文件写入,要用到输出流FileOutputStream
* */
public static void main(String[] args) {
//向文件D:/Hello.txt写入内容
File file = new File("D:/Hello.txt"); try {
//创建输出流
FileOutputStream fos = new FileOutputStream(file);
/把String类型的字符串转化为byte数组的数据保存在输出流中
fos.write("HelloJavaWo 你好世界".getBytes());
fos.flush(刷//输出流
fos.closeQ关闭输出流
} catch (Exception e) { e.printStackTrace();
}
}
}
7、统计一个文件calcCharNum.txt(见附件)中字母'A'和'a出现的总次数import java.io.File;
import java.io.FileInputStream;
public class Test7 {
/**
*统计一个文件calcCharNum.txtt见附件)中字母'A和与出现的总次数
*
*程序分析:
* 读取文件用 FileInputStream
* 一次只读一个字节(一个字母就是一个字节),当字节内容和A或a相等时,相 应的数量加1
* */
public static void main(String[] args) { try {
/添加文件路径
File file = new File("D:/java/calcCharNum.txt");
//创建文件读取流
FileInputStream fis = new FileInputStream(file);
int numA = 0;字母A的数量
int numa = 0制母a的数量
int len =每次读取的字节数量
while ((len=fis.read())!= -1) {
/统计字母a的数量
if (new String((char)len+"").equals("a")) { numa++;
}
/统计字母A的数量
if (new String((char)len+"").equals("A")) { numA++;
}
}
/打印出文件内字母的数量
System.out.println的'数量是:"+numa);
System.out.println 的数量是:"+numA);
System.out.println和"A 出现的总次数:"+(numA+numa));
fis.close关闭输入流
} catch (Exception e) { e.printStackTrace();
}
}
}
8、输入两个文件夹名称,将A文件夹内容全部拷贝到B文件夹,要求使用多线程来操 作。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.xykj.lesson2.FileUtils;
public class Test12 {
/*
*输入两个文件夹名称,将A文件夹内容全部拷贝到B文件夹,要求使用多线程 来操作。
*
*程序分析:
* 1.拷贝文件里面的东西,要分析的东西还是蛮多的,要先建文件夹再拷贝里面 的东西,而且要一层层的来搞
* 2这里也需要文件遍历工具,直接调用第二题的工具类,不再重写
* 3多线程的使用,可以直接在方法里面直接新建线程
* 4对整个文件夹进行复制文件夹分隔符可以用\或/,其他的都是不对的
*所有其中还对输入的分割符进行了替换
*这题看起来比较长,分开看其实也不长
* */
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.printinj"制的文件夹:");
String fromDir = scanner.nex 接收输入
System.out.printinj"制到哪里去:");
String toDir = scanner.nex接;收输入
〃把输入的地址转化为File类型
File fromFile = new File(fromDir);
File toFile = new File(toDir);
//新建线程
new Thread(){
/里面做实际操作
public void run() {
//判断如果要复制的是文件,直接复制就可以了
if (fromFile.isFile()) {
System.out.printlJ复制 单个文件");
copy(fromFile, toFile);
} else {
//要复制文件夹
〃要防止一种无法进行的复制:比如说,要把复制的文件复制 到自己的子文件夹里面
〃举个例子:把D:/java/j文件夹复制到D:/java/jsp文件夹里 面,
//这会导致子文件不断增加的同时,而父文件也要不断增加, 的一个死循环
〃如果反过来,就没事,相当于只是简单的覆盖而已
〃具体实现就是看:目的地地址包含复制的文件夹地址,就不
允许操作
if (toDir.replace("/", "\\").toLowerCase() .startsWith(fromDir.replace("/", "\\").toLowerCase())) { return;
}
〃复制文件(包括文件和文件夹)操作
〃先获取所有的文件(包括文件和文件夹)
List<File> list = FileUtils.getAllFiles(fromDir);
〃创建一个线程池,加快复制的速度
ExecutorService threadPool = Executors.newFixedThreadPool(20);
//需要对每一个文件的路径进行处理
for (File file : list) { 〃复制文件名 String name = file.getAbsolutePath(); 〃把原来的文件路径换成新的文件路径 StringtoName = name.replace(fromFile.getParenoDir + "/");
System.out.println(name变+成"了" + toName);
//如果是文件夹,直接创建 if (file.isDirectory()) { new File(toName).mkdirs();
} else {
〃如果是文件,在线程里面复制 threadPool.execute(new Runnable() { ^Override public void run() {
File copyFile = new File(toName);
〃先要有父文件夹 copyFile.getParentFile().mkdirs();
//开始复制文件 copy(file, copyFile); }
});
}
scanner.close();
);
}.start(开始线程
}
/复制文件的操作
public static void copy(File fromFile, File toFile) {
〃定义一个输入流
FileInputStream fis = null;
〃定义一个输出流
FileOutputStream fos = null;
try {
//把复制地址的File封装后赋值给输入流对象
fis = new FileInputStream(fromFile);
//把目的地的File封装后复制给输出流的对象
fos = new FileOutputStream(toFile);
//创建一个容量,
byte[] buf = new byte[1024];
//每次读取/写入的字节长度
int len = 0;
//边读边写
while ((len = fis.read(buf)) !判断是否还能读到数据
//把输入放到输出流里面
fos.write(buf, 0, len);
}
} catch (E
展开阅读全文