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

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

实验目的   

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

猜你喜欢

转载自blog.csdn.net/qq_42531954/article/details/135391115