针对“Java经典面试题最全汇总208道(三)”的攻略,我将会进行详细的讲解,包括其中每个问题的答案和解释。
标题
Java经典面试题最全汇总208道(三)
代码块
下面是一道比较常见的Java面试题:
public class Test{
public static void main(String[] args) {
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
}
}
问题和解答
问题:在上述代码运行后,输出结果是什么?为什么?
答案:输出结果为 true
和 false
。
这源于字符串常量池带来的影响。在 Java 中,如果字符串常量池中已经有了一个字符串值,而我们想使用一个相同值的字符串, 那么可以使用 intern()
方法。
字符串常量池( String Pool)指的是 JVM 在堆内存中开辟的一块空间,用于存放字符串常量。JVM 在启动时,会将所有用双引号声明的字符串存储在常量池中。
在上面代码的第一行,new StringBuilder("计算机").append("软件")
运行结果创建了一个新的 String 对象,并且这个对象并不在字符串常量池中。而当调用 intern()
方法时,JVM 会判断字符串常量池中是否已经存在 "计算机软件"
这个字符串值,由于之前并没有过创建过该字符串,所以此时会在常量池中创建一个新的字符串对象,返回引用指向这个对象。因此, str1.intern() == str1
返回为 true
。
对于第二行代码,由于字符串 "java"
已经存在于字符串常量池中,所以 str2.intern()
将返回该对象的引用,而 str2
创建了一个新的 String 对象,所以 str2.intern() == str2
的值为 false
。
问题:如何保证只有一个线程能够修改一个特定的变量?
答案:可以使用 synchronized 关键字或者 Lock 接口进行同步。
Java中提供了多种方法来实现多线程间变量的协调和控制。其中最常用的是 synchronized关键字或者 Lock 接口。例如:
public class SimpleCounter{
private int count;
public synchronized void increment(){ // 使用 synchronized 关键字同步
count++;
}
public int getCount(){
return count;
}
}
如上代码中,在 increment()
方法上添加 synchronized 关键字,保证方法的原子性操作,只有一个线程才能修改 count
的值。
public class SimpleCounter{
private int count;
private Lock lock = new ReentrantLock(); // 创建 Lock 对象
public void increment(){
lock.lock(); // 获取锁
try {
count++; // 修改数据
} finally {
lock.unlock(); // 释放锁
}
}
public int getCount(){
return count;
}
}
此外,也可以将 synchronized 代码块,替换为显示锁,比如 ReentrantLock。在 increment()
方法里先获取锁,再释放锁。其他线程等待锁的释放,相当于是对 synchronized 关键字的一个替换。
示例说明:
我们有两个线程去调用 SimpleCounter
的 increment()
方法,通过 synchronized 或者 Lock 进行同步,就可以确保只有一个线程调用该方法时,才会改变 count
值。
例如,下面这个示例,开启两个线程对象,通过 incrementCount()
方法对 SimpleCounter
实例对象的 "count"
字段进行修改。由于使用了 synchronized 关键字,所以保证了方法的原子性操作。两个线程调用 incrementCount()
方法后,最终得到的结果应该是 2000000
。
public class Main {
public static void main(String[] args) throws InterruptedException {
final SimpleCounter simpleCounter = new SimpleCounter();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
simpleCounter.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
simpleCounter.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(simpleCounter.getCount());
}
}
在这个例子里,我们定义了一个 SimpleCounter
类和两个线程对象。这些线程使用同一个 SimpleCounter
对象来执行任务,调用它的 increment()
方法,使得 "count" 字段加上 1。最后通过 join()
方法使两个线程拼接起来,输出结果为 2000000
。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java经典面试题最全汇总208道(三) - Python技术站