java基础常见面试题系列,61-70

61、编写多线程程序有几种实现方式?

Java 5 以前实现多线程有两种实现方法:一种是继承 Thread 类;另一种是实现 Runnable 接口。两种方式都要通过重写 run()方法来定义线程的行为,推荐使用 后者,因为 Java 中的继承是单继承,一个类有一个父类,如果继承了 Thread 类 就无法再继承其他类了,显然使用 Runnable 接口更为灵活。

62、synchronized 关键字的用法?

synchronized 关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用 synchronized(对象) { … }定义同步代码块,或者在声明方法时 将 synchronized 作为方法的修饰符。在第 60 题的例子中已经展示了 synchronized 关键字的用法。

63、举例说明同步和异步。

如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正 在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线 程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好 的例子)。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并 且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异 步途径往往更有效率。事实上,所谓的同步就是指阻塞式操作,而异步就是非阻 塞式操作。

64、启动一个线程是调用 run()还是 start()方法?

启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态, 这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行。run()方 法是线程启动后要进行回调(callback)的方法。

65、什么是线程池(thread pool)?

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内 存资源或者其它更多资源。在 Java 中更是如此,虚拟机将试图跟踪每一个对象, 以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽 可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就 是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的 线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完 毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。 Java 5+中的 Executor 接口定义一个执行线程的工具。它的子类型即线程池接口 是 ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理 不是很清楚的情况下,因此在工具类 Executors 面提供了一些静态工厂方法,生 成一些常用的线程池,如下所示:

newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只 有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线 程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执 行顺序按照任务的提交顺序执行。

newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创 建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就 会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小 超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)的 线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程 池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说 JVM) 能够创建的最大线程大小。

newScheduledThreadPool:创建一个大小无限的线程池。此线程池支 持定时以及周期性执行任务的需求。

newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持 定时以及周期性执行任务的需求。

66、线程的基本状态以及状态之间的关系?

基本状态:

  1. 新建:线程对象创建
  2. 就绪:通过线程的start方法启动线程,线程就处于就绪状态,等待线程调度,获取CPU的执行权。
  3. 运行:线程获得CPU的执行权,处于运行中。
  4. 阻塞:线程在执行期间,因为某种原因(休眠,礼让,时间到达),暂时失去CPU 的执行权,等待再次获得CPU的执行权。
  5. 死亡:当run(),main()执行结束之后,或者因为线程发生异常,终止执行。线程死亡之后不能在复生。

 

67、简述 synchronized 和 java.util.concurrent.locks.Lock 的异同?

Lock 是 Java 5 以后引入的新的 API,和关键字 synchronized 相比主要相同点: Lock 能完成 synchronized 所实现的所有功能;主要不同点:Lock 有比 synchronized 更精确的线程语义和更好的性能,而且不强制性的要求一定要获得 锁。synchronized 会自动释放锁,而 Lock 一定要求程序员手工释放,并且最好 在 finally 块中释放(这是释放外部资源的最好的地方)。

68、Java 中如何实现序列化,有什么意义?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流 化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。 序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会 存在数据乱序的问题)。 要实现序列化,需要让一个类实现 Serializable 接口,该接口是一个标识性接口, 标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通 过 writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要 反序列化则可以用一个输入流建立对象输入流,然后通过 readObject 方法从流中 读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆。

69、Java 中有几种类型的流?

字节流和字符流。字节流继承于 InputStream、OutputStream,字符流继承于 Reader、Writer。在 java.io 包中还有许多其他的流,主要是为了提高性能和使 用方便。关于 Java 的 I/O 需要注意的有两点:一是两种对称性(输入和输出的对 称性,字节和字符的对称性);二是两种设计模式(适配器模式和装潢模式)。 另外 Java 中的流不同于 C#的是它只有一个维度一个方向。

面试题 - 编程实现文件拷贝。(这个题目在笔试的时候经常出现,下面的代码给 出了两种实现方案)


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public final class MyUtil {
	private MyUtil() {
		throw new AssertionError();
	}

	public static void fileCopy(String source, String target) throws IOException {
		try (InputStream in = new FileInputStream(source)) {
			try (OutputStream out = new FileOutputStream(target)) {
				byte[] buffer = new byte[4096];
				int bytesToRead;
				while ((bytesToRead = in.read(buffer)) != -1) {
					out.write(buffer, 0, bytesToRead);
				}
			}
		}
	}

	public static void fileCopyNIO(String source, String target) throws IOException {
		try (FileInputStream in = new FileInputStream(source)) {
			try (FileOutputStream out = new FileOutputStream(target)) {
				FileChannel inChannel = in.getChannel();
				FileChannel outChannel = out.getChannel();
				ByteBuffer buffer = ByteBuffer.allocate(4096);
				while (inChannel.read(buffer) != -1) {
					buffer.flip();
					outChannel.write(buffer);
					buffer.clear();
				}
			}
		}
	}
}

70、写一个方法,输入一个文件名和一个字符串,统计这个字 符串在这个文件中出现的次数。 


import java.io.BufferedReader;
import java.io.FileReader;

public final class MyUtil {
// 工具类中的方法都是静态方式访问的因此将构造器私有不允许创建对象(绝对好习惯)
	private MyUtil() {
		throw new AssertionError();
	}

	/**
	 * 统计给定文件中给定字符串的出现次数
	 *
	 * @param filename 文件名
	 * @param word     字符串
	 * @return 字符串在文件中出现的次数
	 */
	public static int countWordInFile(String filename, String word) {
		int counter = 0;
		try (FileReader fr = new FileReader(filename)) {
			try (BufferedReader br = new BufferedReader(fr)) {
				String line = null;
				while ((line = br.readLine()) != null) {
					int index = -1;
					while (line.length() >= word.length() && (index = line.indexOf(word)) >= 0) {
						counter++;
						line = line.substring(index + word.length());
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return counter;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值