Java相关一些技术问题
一、使用Java多线程顺序打印10个数字
要使用多线程在Java中顺序打印10个数字,你可以创建多个线程并使用线程同步机制来确保它们按照指定的顺序执行。下面是一个示例代码:
public class SequentialPrinting {
private static final Object lock = new Object();
private static int counter = 1;
public static void main(String[] args) {
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(new NumberPrinter(i + 1));
threads[i].start();
}
}
private static class NumberPrinter implements Runnable {
private final int number;
public NumberPrinter(int number) {
this.number = number;
}
@Override
public void run() {
synchronized (lock) {
while (counter != number) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(number);
counter++;
lock.notifyAll();
}
}
}
}
在这段代码中,我们创建了一个名为SequentialPrinting
的类。它包含一个共享的静态计数器counter
和一个共享的锁对象lock
。我们创建了一个NumberPrinter
类作为线程的实现,并在其run
方法中实现了打印数字的逻辑。
在main
方法中,我们创建了10个线程,并分别给它们分配数字1到10。每个线程在执行时,首先通过synchronized
关键字对lock
对象进行同步,然后进入一个循环,直到counter
的值等于当前线程分配的数字。
在循环内部,线程调用lock.wait()
方法进行等待,直到它被唤醒并且counter
的值等于当前线程分配的数字。一旦满足条件,线程打印当前数字并递增counter
的值。最后,线程调用lock.notifyAll()
方法唤醒其他等待的线程。
二、Java双重检查单例的坑
双重检测单例是一种在多线程环境下实现延迟加载的单例模式。下面是一种使用双重检测的方式实现的双重检测单例:
public class DoubleCheckedSingleton {
private static volatile DoubleCheckedSingleton instance;
private DoubleCheckedSingleton() {
// 私有构造函数
}
public static DoubleCheckedSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedSingleton();
}
}
}
return instance;
}
}
为了正确地处理指令重排序问题(否则instance已经有引用但是并未初始化),instance
变量需要使用volatile
关键字进行修饰。这样可以确保在使用instance
时,它已经被正确地初始化。
三、循环删除List元素的坑
在循环中删除元素可能会导致索引错位或ConcurrentModificationException异常。
3.1 使用错误的循环索引
// 错误示例
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("B")) {
list.remove(i); // 错误的删除方式
}
}
// 预期删除元素 "B",但实际上删除了元素 "C",索引错位
// 正确示例
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("B")) {
iterator.remove(); // 使用迭代器的 remove() 方法
}
}
// 正确删除元素 "B",不会导致索引错位
```
3.2 直接使用了for删除
// 错误示例
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (String element : list) {
if (element.equals("B")) {
list.remove(element); // 错误的删除方式
}
}
// 抛出 ConcurrentModificationException 异常
// 正确示例
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (element.equals("B")) {
iterator.remove(); // 使用迭代器的 remove() 方法
}
}
// 正确删除元素 "B",不会抛出异常
```
四、Arrays.asList()
Arrays.asList()
返回的是一个固定大小的List,不支持结构性修改操作(添加或删除元素),任何尝试修改其大小的操作都会导致UnsupportedOperationException
异常。以下是一个使用错误的示例:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);
list.add("D"); // 错误的添加操作
System.out.println(list);
}
}
正确使用的实例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
String[] array = {"A", "B", "C"};
List<String> list = new ArrayList<>(Arrays.asList(array));
list.add("D"); // 正确的添加操作
System.out.println(list);
}
}
评论区