实验名称??? 实验四 多线程与并发
实验目的???
1. 理解进程与线程的概念,掌握创建线程对象的方法。
2. 熟练使用线程类相关API以控制线程对象的状态。
3. 掌握实现线程同步的方法。??
实验内容
使用继承Thread类创建线程
public class ThreadExample1 extends Thread {
??? @Override
??? public void run() {
??????? try {
??????????? int sleepTime = (int) (Math.random() * 1000);
??????????? Thread.sleep(sleepTime);
??????????? System.out.println("Thread " + this.getId() + " finished after " + sleepTime + "ms");
??????? } catch (InterruptedException e) {
??????????? e.printStackTrace();
??????? }
??? }
???
public static void main(String[] args) {
??????? for (int i = 0; i < 5; i++) {
??????????? Thread thread = new ThreadExample1();
??????????? thread.start();
??????? }
??? }
}
使用实现Runnable接口创建线程
public class RunnableExample2 implements Runnable {
??? @Override
??? public void run() {
??????? try {
??????????? int sleepTime = (int) (Math.random() * 1000);
??????????? Thread.sleep(sleepTime);
??????????? System.out.println("Thread " + Thread.currentThread().getId() + " finished after " + sleepTime + "ms");
??????? } catch (InterruptedException e) {
??????????? e.printStackTrace();
??????? }
??? }
??? public static void main(String[] args) {
??????? for (int i = 0; i < 5; i++) {
??????????? Thread thread = new Thread(new RunnableExample2());
??????????? thread.start();
??????? }
??? }
}
2. 复现例11.5:教师唤醒班长,班长唤醒汤姆。与教材中给的代码不同,分别写出教师、班长、汤姆三个线程类,并在Demo类中创建教师、班长、汤姆三个线程对象,演示这三个线程对象的并发:教师唤醒班长,班长唤醒汤姆。
public class TeacherThread extends Thread {
??? private TomThread tomThread;
??? public TeacherThread(TomThread tomThread) {
??????? this.tomThread = tomThread;
??? }
??? @Override
??? public void run() {
??????? System.out.println("Teacher is waking up the Class Leader.");
??????? tomThread.interrupt();
??? }
}
public class ClassLeaderThread extends Thread {
??? private TomThread tomThread;
??? public ClassLeaderThread(TomThread tomThread) {
??????? this.tomThread = tomThread;
??? }
??? @Override
??? public void run() {
??????? try {
??????????? sleep(2000); // Class Leader sleeps for 2 seconds
??????????? System.out.println("Class Leader is waking up Tom.");
??????????? tomThread.interrupt();
??????? } catch (InterruptedException e) {
??????????? System.out.println("Class Leader is woken up early.");
??????? }
??? }
}
public class TomThread extends Thread {
??? @Override
??? public void run() {
??????? try {
??????????? while (true) {
??????????????? sleep(1000); // Tom sleeps for 1 second
??????????????? System.out.println("Tom is still sleeping.");
??????????? }
??????? } catch (InterruptedException e) {
??????????? System.out.println("Tom is woken up by someone.");
??????? }
??? }
}
public class Demo {
??? public static void main(String[] args) {
??????? TomThread tomThread = new TomThread();
??????? ClassLeaderThread classLeaderThread = new ClassLeaderThread(tomThread);
??????? TeacherThread teacherThread = new TeacherThread(tomThread);
??????? tomThread.start();
??????? classLeaderThread.start();
??????? teacherThread.start();
??? }
}
3.
(1)复现案例实践12:模拟管程方式实现1个生产者消费者问题。
package ahpu.t3;
import java.util.LinkedList;
class Monitor {
??? private LinkedList<Integer> buffer = new LinkedList<>();
??? private int capacity = 5;
??? public synchronized void produce() {
??????? while (buffer.size() == capacity) {
??????????? try {
??????????????? wait();
??????????? } catch (InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??????? int item = (int) (Math.random() * 100);
??????? buffer.add(item);
??????? System.out.println("Produced: " + item);
??????? notify();
??? }
??? public synchronized void consume() {
??????? while (buffer.isEmpty()) {
??????????? try {
??????????????? wait();
??????????? } catch (InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??????? int item = buffer.remove();
??????? System.out.println("Consumed: " + item);
??????? notify();
??? }
}
class Producer extends Thread {
??? private Monitor monitor;
??? public Producer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.produce();
??????? }
??? }
}
class Consumer extends Thread {
??? private Monitor monitor;
??? public Consumer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.consume();
??????? }
??? }
}
public class Demo {
??? public static void main(String[] args) {
??????? Monitor monitor = new Monitor();
??????? Producer producer = new Producer(monitor);
??????? Consumer consumer = new Consumer(monitor);
??????? producer.start();
??????? consumer.start();
??? }
}
(2)扩展1:模拟管程方式实现n个缓冲区的生产者消费者问题。
package ahpu.t3.t2;
import java.util.LinkedList;
class Monitor {
??? private LinkedList<Integer> buffer = new LinkedList<>();
??? private int capacity;
??? public Monitor(int capacity) {
??????? this.capacity = capacity;
? ??}
??? public synchronized void produce() {
??????? while (buffer.size() == capacity) {
??????????? try {
??????????????? wait();
??????????? } catch (InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??????? int item = (int) (Math.random() * 100);
??????? buffer.add(item);
??????? System.out.println("Produced: " + item);
??????? notify();
??? }
??? public synchronized void consume() {
??????? while (buffer.isEmpty()) {
??????????? try {
??????????????? wait();
??????????? } catch (InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??????? int item = buffer.remove();
??????? System.out.println("Consumed: " + item);
??????? notify();
??? }
}
class Producer extends Thread {
??? private Monitor monitor;
??? public Producer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.produce();
??????? }
??? }
}
class Consumer extends Thread {
??? private Monitor monitor;
??? public Consumer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.consume();
??????? }
??? }
}
public class Demo {
??? public static void main(String[] args) {
??????? int numBuffers = 5; // Number of buffer spaces
??????? Monitor monitor = new Monitor(numBuffers);
??????? int numProducers = 3; // Number of producer threads
??????? int numConsumers = 2; // Number of consumer threads
??????? for (int i = 0; i < numProducers; i++) {
??????????? Producer producer = new Producer(monitor);
??????????? producer.start();
??????? }
??????? for (int i = 0; i < numConsumers; i++) {
??????????? Consumer consumer = new Consumer(monitor);
??????????? consumer.start();
??????? }
??? }
}
?
(3)扩展2:模拟PV操作实现n个缓冲区的生产者消费者问题。
package ahpu.t3.t3;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;
class Monitor {
??? private LinkedList<Integer> buffer = new LinkedList<>();
??? private int capacity;
??? private Semaphore emptySlots;
??? private Semaphore filledSlots;
??? private Semaphore mutex;
??? public Monitor(int capacity) {
??????? this.capacity = capacity;
??????? this.emptySlots = new Semaphore(capacity);
??????? this.filledSlots = new Semaphore(0);
??????? this.mutex = new Semaphore(1);
??? }
??? public void produce() {
??????? try {
??????????? emptySlots.acquire();
??????????? mutex.acquire();
??????????? int item = (int) (Math.random() * 100);
??????????? buffer.add(item);
??????????? System.out.println("Produced: " + item);
??????????? mutex.release();
??????????? filledSlots.release();
??????? } catch (InterruptedException e) {
??????????? e.printStackTrace();
??????? }
??? }
??? public void consume() {
??????? try {
??????????? filledSlots.acquire();
??????????? mutex.acquire();
??????????? int item = buffer.remove();
??????????? System.out.println("Consumed: " + item);
??????????? mutex.release();
??????????? emptySlots.release();
??????? } catch (InterruptedException e) {
??????????? e.printStackTrace();
??????? }
??? }
}
class Producer extends Thread {
??? private Monitor monitor;
??? public Producer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.produce();
??????? }
??? }
}
class Consumer extends Thread {
??? private Monitor monitor;
??? public Consumer(Monitor monitor) {
??????? this.monitor = monitor;
??? }
??? @Override
??? public void run() {
??????? while (true) {
??????????? monitor.consume();
??????? }
??? }
}
public class Demo {
??? public static void main(String[] args) {
??????? int numBuffers = 5; // Number of buffer spaces
??????? Monitor monitor = new Monitor(numBuffers);
??????? int numProducers = 3; // Number of producer threads
??????? int numConsumers = 2; // Number of consumer threads
??????? for (int i = 0; i < numProducers; i++) {
??????????? Producer producer = new Producer(monitor);
??????????? producer.start();
??????? }
??????? for (int i = 0; i < numConsumers; i++) {
??????????? Consumer consumer = new Consumer(monitor);
??????????? consumer.start();
??????? }
??? }
}
实验程序及结果(附录)
思考
关键字synchronized有哪几种用法?各自的逻辑是什么?
关键字 `synchronized` 在 Java 中有三种主要用法,各自的逻辑如下:
1. **实例方法同步**:
?? ```java
?? public synchronized void myMethod() {
?????? // 方法体
?? }
?? ```
?? 这种用法将整个实例方法标记为同步方法。当一个线程调用这个方法时,它将获得实例对象的锁,其他线程将被阻塞,直到当前线程执行完该方法并释放锁。
2. **同步块**:
?? ```java
?? public void myMethod() {
?????? synchronized (lockObject) {
?????????? // 同步块的代码
?????? }
?? }
?? ```
?? 这种用法允许你创建一个同步块,只有当线程获得了指定对象(`lockObject`)的锁时才能执行同步块中的代码。这允许更细粒度的控制,不必锁住整个方法,而只锁住需要同步的代码块。
3. **静态方法同步**:
?? ```java
?? public static synchronized void myStaticMethod() {
?????? // 方法体
?? }
?? ```
?? 静态方法同步使用 `synchronized` 关键字来修饰静态方法。它将锁定整个类的所有实例,而不是特定实例对象。这意味着只有一个线程能够同时执行任何一个静态同步方法。
`synchronized` 关键字的作用是确保多个线程之间的协调和互斥访问共享资源。当一个线程进入同步块或方法时,它会尝试获取对象的锁,如果锁已被其他线程占用,线程将被阻塞,直到锁被释放。这确保了共享资源的安全访问,防止多个线程同时修改共享数据,从而避免数据竞争和不一致的结果。