练习题:多线程交替输出 “A” 和 “B”
题目:
使用两个线程,要求它们交替输出字母 “A” 和 “B”,且每次输出后线程进入等待状态,休眠 500 毫秒后再次交替输出。使用 synchronized
、wait()
和 notify()
实现线程间的通信,确保线程按顺序输出,避免两个线程同时输出或遗漏输出。
要求:
- 每个线程每隔 500 毫秒输出一次。
- 线程 A 输出 “A”,线程 B 输出 “B”,两个线程交替运行。
- 程序可以持续运行。
参考答案:
package thread;
public class lx0 {
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
while (true) {
try {
Thread.sleep(500); // 休眠500毫秒
lock.notify(); // 唤醒等待的线程
System.out.println("A");
lock.wait(); // 让当前线程进入等待状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
new Thread(() -> {
synchronized (lock) {
while (true) {
try {
Thread.sleep(500); // 休眠500毫秒
lock.notify(); // 唤醒等待的线程
System.out.println("B");
lock.wait(); // 让当前线程进入等待状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
解释:
1. 线程同步:两个线程使用同一个 lock
对象,通过 synchronized
关键字来确保线程之间的同步,保证同一时刻只有一个线程能够进入临界区。
2. 线程通信:使用 wait()
和 notify()
实现线程间的通信,线程 A 输出 “A” 后进入等待,线程 B 输出 “B” 后唤醒线程 A,形成交替输出的效果。
3. 休眠:使用 Thread.sleep(500)
让线程每次输出后休眠 500 毫秒。
输出示例:
A
B
A
B
...
以下是一些与多线程相关的练习题,以及相应的参考答案。这些题目涵盖了多线程的基本概念、同步、线程间通信等方面的内容,适合巩固多线程编程的知识。
1. 练习题:实现线程交替打印
题目:使用两个线程,交替打印 1-100 的数字。
参考答案:
public class AlternatePrinting {
static final Object lock = new Object();
static int count = 1;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
while (count <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": " + count++);
lock.notify();
if (count <= 100) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
Thread t2 = new Thread(() -> {
while (count <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": " + count++);
lock.notify();
if (count <= 100) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t1.start();
t2.start();
}
}
解释:该程序使用两个线程交替打印数字。通过共享 count
变量和使用 wait()
、notify()
来实现线程同步和交替执行。
2. 练习题:多线程求和
题目:给定一个包含 100 个元素的数组,要求使用 10 个线程并行计算数组的元素之和。
参考答案:
import java.util.concurrent.atomic.AtomicInteger;
public class ParallelSum {
static final int[] array = new int[100];
static final AtomicInteger sum = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
array[i] = i + 1; // 初始化数组,元素为1到100
}
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
final int start = i * 10;
final int end = start + 10;
threads[i] = new Thread(() -> {
for (int j = start; j < end; j++) {
sum.addAndGet(array[j]);
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("Total sum: " + sum);
}
}
解释:此程序将数组划分成 10 个部分,每个线程计算其中一部分的和,并使用 AtomicInteger
确保并发加操作的线程安全性。
3. 练习题:生产者-消费者问题
题目:使用两个线程实现生产者和消费者模式,生产者生成整数,消费者消费整数。生产者最多生成 10 个整数后等待,消费者消费完 10 个整数后继续消费。
参考答案:
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer {
static final Queue<Integer> queue = new LinkedList<>();
static final int MAX_SIZE = 10;
public static void main(String[] args) {
Thread producer = new Thread(() -> {
int value = 0;
while (true) {
synchronized (queue) {
while (queue.size() == MAX_SIZE) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced: " + value);
queue.offer(value++);
queue.notifyAll();
}
}
});
Thread consumer = new Thread(() -> {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int value = queue.poll();
System.out.println("Consumed: " + value);
queue.notifyAll();
}
}
});
producer.start();
consumer.start();
}
}
解释:该程序实现了经典的生产者-消费者模式,使用 wait()
和 notifyAll()
来协调线程之间的通信,保证生产者和消费者交替执行。
4. 练习题:使用线程池并发执行任务
题目:使用 Java 的 ExecutorService
实现一个简单的线程池,执行 10 个任务,每个任务打印当前线程的名称。
参考答案:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + " is executing task " + taskId);
});
}
executorService.shutdown();
}
}
解释:此代码使用 Executors.newFixedThreadPool(3)
创建了一个包含 3 个线程的固定大小的线程池,并提交了 10 个任务。
5. 练习题:多线程死锁
题目:编写一个有死锁的 Java 程序,并解释死锁的原因。
参考答案:
public class DeadlockExample {
static final Object lock1 = new Object();
static final Object lock2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
});
t1.start();
t2.start();
}
}
解释:该程序展示了一个简单的死锁场景。线程 1 拿到了 lock1
,然后试图获取 lock2
;同时,线程 2 拿到了 lock2
,试图获取 lock1
。由于两个线程互相等待,导致死锁。
这些练习题涵盖了多线程的基本概念和一些常见的多线程编程问题,可以帮助你更好地理解 Java 多线程编程。