【Java】实验四 多线程与并发

2024-01-09 02:18:18

实验名称??? 实验四 多线程与并发

实验目的???

1. 理解进程与线程的概念,掌握创建线程对象的方法。

2. 熟练使用线程类相关API以控制线程对象的状态。

3. 掌握实现线程同步的方法。??

实验内容

  1. 基于继承Thread类、实现Runnable接口两种方式创建线程,验证线程的并发执行:新建多个线程,每个线程等待随机长的时间后输出该线程运行结束的信息。

使用继承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` 关键字的作用是确保多个线程之间的协调和互斥访问共享资源。当一个线程进入同步块或方法时,它会尝试获取对象的锁,如果锁已被其他线程占用,线程将被阻塞,直到锁被释放。这确保了共享资源的安全访问,防止多个线程同时修改共享数据,从而避免数据竞争和不一致的结果。

文章来源:https://blog.csdn.net/qq_42531954/article/details/135391115
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。