目录
- 题目
- wait()、notify()和notifyAll()方法的特性和使用场景
- wait() 方法
- notify() 方法
- notifyAll() 方法
- 使用场景
 
- 注意事项
 
 
题目
选自牛客网
 1.下面关于JAVA的垃圾回收机制,正确的是( )
 A.当调用“System.gc()”来强制回收时,系统会立即回收垃圾
 B.垃圾回收不能确定具体的回收时间
 C.程序可明确地标识某个局部变量的引用不再被使用
 D.程序可以显式地立即释放对象占有的内存
正确答案:B
正确的描述是选项B:“垃圾回收不能确定具体的回收时间”。Java的垃圾回收机制是自动运行的,它负责回收不再使用的对象所占用的内存。然而,垃圾回收的具体触发时间和频率是不确定的,由垃圾回收器根据系统的运行状态自动决定。即使调用了System.gc()方法建议进行垃圾回收,也不能保证垃圾回收会立即执行,这只是一个建议,垃圾回收器可以选择忽略。因此,选项B是正确的。选项A和D的描述与Java垃圾回收机制的实际行为不符,而选项C描述的是可以通过将引用设为null来暗示对象不再使用,但这并不是强制垃圾回收,垃圾回收器仍然会根据自己的策略来决定何时回收这些对象。
2.java中Hashtable, Vector, TreeSet, LinkedList哪些线程是安全的?
 A.Hashtable
 B.Vector
 C.TreeSet
 D.LinkedList
正确答案:AB
在Java中,
Hashtable和Vector是早期设计的集合类,它们内部的方法是同步的,因此它们是线程安全的。这意味着它们可以在多线程环境中共享而不需要额外的同步措施。然而,TreeSet和LinkedList并不提供内置的线程安全保障,它们的方法是非同步的,因此在多线程环境中共享时需要额外的同步控制,或者使用线程安全的包装类,如Collections.synchronizedSet()和Collections.synchronizedList(),来包装这些集合,以提供线程安全性。因此,正确答案是 A 和 B:
Hashtable和Vector是线程安全的集合类。
3.下面哪些写法能在 java8 中编译执行()
A.dir.listFiles((File f)->f.getName().endsWith(“.Java”));
 B.dir.listFiles((File f)=>f.getName().endsWith(“.Java”));
 C.dir.listFiles((_.getName().endsWith(“.Java”)));
 D.dir.listFiles( f->f.getName().endsWith(“.Java”));
ad
形参列表:
- 形参列表定义了Lambda表达式接受的参数。参数类型可以被省略,Java编译器会根据上下文推断它们的类型。
- 如果Lambda表达式只有一个参数,那么甚至可以省略圆括号。例如,
(String s) -> s.length()可以简化为String s -> s.length()。
箭头(→):
- 箭头是Lambda表达式的固定组成部分,用于分隔形参列表和代码块。它表示从参数到执行代码的转换。
代码块:
- 代码块包含了Lambda表达式执行的逻辑。如果代码块仅包含一条语句,那么可以省略花括号。
- 如果代码块中的语句是单一的返回语句,那么
return关键字也可以被省略,Lambda表达式会自动返回这条语句的结果。基于这些规则,选项A和D的Lambda表达式是正确的,它们遵循了正确的语法和结构,能够编译执行。例如:
- 选项A:
dir.listFiles((File f) -> f.getName().endsWith(".Java"));- 选项D:
dir.listFiles(f -> f.getName().endsWith(".Java"));这两个选项中,Lambda表达式接受一个
File类型的参数,并返回一个布尔值,表示文件名是否以".Java"结尾,这符合listFiles方法需要的过滤器逻辑。
4.以下哪几种方式可用来实现线程间通知和唤醒:( )
 A.Object.wait/notify/notifyAll
 B.ReentrantLock.wait/notify/notifyAll
 C.Condition.await/signal/signalAll
 D.Thread.wait/notify/notifyAll
 正确答案:AC
wait()、notify()和notifyAll()方法的特性和使用场景
wait()、notify()和notifyAll()是Java中用于线程间通信的内置方法,它们定义在Object类中,因此适用于所有Java对象。这些方法与同步机制紧密相关,它们必须在同步块或同步方法中被调用,以确保线程安全。
wait() 方法
- wait()方法允许一个线程放弃对象的锁,并等待直到另一个线程通知该对象锁已被释放。
- 当一个线程调用对象的wait()方法时,它会立即释放该对象的锁,并进入到该对象的等待集合(wait set)中。
- 调用wait()方法必须在同步控制块或同步方法中进行,以避免违反锁的独占性。
notify() 方法
- notify()方法用于唤醒在同一个对象的等待集合中等待的单个线程。
- 调用notify()方法的线程必须持有该对象的锁,但在调用后会立即释放锁,使得等待集合中的一个线程可以尝试重新获取锁。
- 被唤醒的线程将继续执行,但它能否成功获取锁取决于锁的可用性和其他线程的竞争。
notifyAll() 方法
- notifyAll()方法用于唤醒在同一个对象的等待集合中等待的所有线程。
- 与notify()方法类似,调用notifyAll()的线程必须持有该对象的锁,并在调用后释放锁。
- 所有等待集合中的线程都会被唤醒,但它们仍然需要竞争锁以继续执行。
使用场景
- wait()、- notify()和- notifyAll()通常用于实现生产者-消费者问题、读写锁、条件变量等多线程同步场景。
- 这些方法可以帮助线程在某个条件尚未满足时暂停执行,并在条件满足时恢复执行,从而实现线程间的协作。
注意事项
- 在使用wait()、notify()和notifyAll()时,应当小心避免死锁和竞态条件。
- 通常建议在等待条件前使用循环检查来确认条件是否真的已经满足,以防止虚假唤醒(spurious wakeup)。
- 这些方法在多线程编程中是非常强大的工具,但也需要谨慎使用,以确保程序的正确性和性能。
3.以下代码输出的是:
 public class SendValue{
 public String str=“6”;
 public static void main(String[] args) {
 SendValue sv=new SendValue();
 sv.change(sv.str);
 System.out.println(sv.str);
 }
 public void change(String str) {
 str=“10”;
 }
 }
A.6
 B.10
 C.都不对
 D.16
正确答案:A
代码中的change方法接受一个String类型的参数str,并将其修改为"10"。然而,这个方法内部的str变量是局部变量,它与类的成员变量str是两个不同的引用。因此,即使局部变量str的值被修改,类的成员变量str的值仍然保持不变,其值为"6"。所以,当打印出sv.str的值时,输出结果是6。这说明Java中字符串是不可变的,修改字符串实质上是创建了一个新的字符串对象,而不会改变原始字符串对象的值。因此,正确答案是A.6。