【问题标题】:Reader Writers prob using Semaphores in Java-wrong thread name, unable to run concurrently and show concurrencyReader Writers prob using Semaphores in Java-wrong thread name,无法并发运行并显示并发
【发布时间】:2016-05-01 17:08:14
【问题描述】:

虽然这看起来像是一个重复的问题,但在互联网上使用 Java 中的信号量并没有一个正确的工作实现 Reader Writer 的问题。我找到的最接近的是this,其中给出了替代方案作为答案,但不使用信号量。

我是 Java 多线程的新手,所以请多多包涵。这是我的代码:

import java.util.concurrent.Semaphore;

class ReaderWritersProblem {

    static Semaphore readLock = new Semaphore(1);
    static Semaphore writeLock = new Semaphore(1);
    static int readCount = 0;

    static class Read implements Runnable {
        @Override
        public synchronized void run() {
            try {
                readLock.acquire();
                readCount++;
                if (readCount == 1) {
                    writeLock.acquire();
                }
                System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
                Thread.sleep(1500);
                System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
                readLock.release();
                readCount--;
                if(readCount == 0) {
                    writeLock.release();
                }
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    static class Write implements Runnable {
        @Override
        public synchronized void run() {
            try {
                writeLock.acquire();
                System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
                Thread.sleep(2500);
                System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
                writeLock.release();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Read read = new Read();
        Write write = new Write();
        Thread t1 = new Thread(read);
        t1.setName("thread1");
        Thread t2 = new Thread(read);
        t2.setName("thread2");
        Thread t3 = new Thread(write);
        t3.setName("thread2");
        Thread t4 = new Thread(read);
        t4.setName("thread4");
        t1.run();
        t2.run();
        t3.run();
        t4.run();
    }
}

我正在创建 4 个线程,3 个用于读取,1 个用于写入。但是,输出是这样的:

主线程正在阅读
主线程已完成阅读
线程 main 正在阅读
线程 main 已完成阅读
线程 main is WRITING
线程 main 已完成 WRITING
Thread main is READING
主线程已读完

返回的线程名称是'main'。此外,所有这些似乎都没有同时执行。我如何更正仅使用信号量来实现 Reader Writers 问题?使用ReentrantReadLock 等会很简单,但会超出问题的目的,它清楚地表明使用信号量来实现问题。谢谢

编辑:另外,如何显示多个线程阅读?我正在一一得到执行结果。

编辑:更正的代码:我已经更正了算法。希望对此进行一些评论。

import java.util.concurrent.Semaphore;

class ReaderWritersProblem {

    static Semaphore readLock = new Semaphore(1);
    static Semaphore writeLock = new Semaphore(1);
    static int readCount = 0;

    static class Read implements Runnable {
        @Override
        public void run() {
            try {
                //Acquire Section
                readLock.acquire();
                readCount++;
                if (readCount == 1) {
                    writeLock.acquire();
                }
                readLock.release();

                //Reading section
                System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
                Thread.sleep(1500);
                System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");

                //Releasing section
                readLock.acquire();
                readCount--;
                if(readCount == 0) {
                    writeLock.release();
                }
                readLock.release();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    static class Write implements Runnable {
        @Override
        public void run() {
            try {
                writeLock.acquire();
                System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
                Thread.sleep(2500);
                System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
                writeLock.release();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Read read = new Read();
        Write write = new Write();
        Thread t1 = new Thread(read);
        t1.setName("thread1");
        Thread t2 = new Thread(read);
        t2.setName("thread2");
        Thread t3 = new Thread(write);
        t3.setName("thread3");
        Thread t4 = new Thread(read);
        t4.setName("thread4");
        t1.start();
        t3.start();
        t2.start();
        t4.start();
    }
}

【问题讨论】:

    标签: java multithreading concurrency


    【解决方案1】:

    我认为您的问题与为什么这段代码没有同时执行有关。这是因为您必须调用方法 t1.start() 而不是 t1.run() (相应地,对于所有其他线程也是如此)。 t1.run() 将在主线程的上下文中运行 run() 方法,而不是在新线程中。

    当您已经使用二进制信号量保护代码时,我看不到同步方法的意义。两个线程将无法同时获取二进制信号量,只要线程不盲目地释放信号量,您的代码将是安全的。这违背了拥有多个阅读器线程的整个目的。

    更新了评论中的新问题 - 如果您希望多个阅读器线程访问同一部分,那么您不应使用二进制信号量,而是使用具有更大值(最好等于阅读器线程数)的信号量。所有这些线程都可以获取信号量并在完成后释放它们。当许多阅读器线程处于活动状态时,还必须特别注意不要使编写器线程饿死。这可以通过多种方式完成 - 只需为读者谷歌搜索 - 作家问题,您会发现如何做到这一点。

    【讨论】:

    • 这解决了部分问题,谢谢。请参考更新问题。如何获得显示并发线程读取的输出?
    • 好的,谢谢。此外,我希望输出类似于“线程 2 正在读取,线程 3 正在读取,线程 2 已完成读取”等以显示多个线程可以同时读取。在这种情况下,我必须将readLock 信号量的上限更改为 > 1 对吗?其余的代码也可以吗?
    • 我已经更新了答案。但是我仍然不明白您的部分代码,例如您为什么要尝试在读取器线程中获取写入器锁。所以我坚持使用你的代码中的一般 cmets。
    • 如果您有时间,我想知道对代码的最佳更改是什么。另外,我应该将AtomicInteger 用于readCount 变量吗?
    • 在读取线程中获取写入锁,因为如果没有。读者数 > 1,则作者无法访问临界区。我参考了维基百科上的伪代码here:
    猜你喜欢
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多