Java-允许一个线程更新值,其他线程等待和跳过关键部分 [英] Java- Allow one thread to update a value, others to wait and skip critical section

查看:140
本文介绍了Java-允许一个线程更新值,其他线程等待和跳过关键部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,我只允许一个线程说更新变量.

Hi I have a situation in which I have to allow only one thread to say update a variable.

有一个触发器,该触发器可能调用多个线程来更新此变量,但是更新仅应由第一个线程执行一次,无论哪个到达关键部分.

There is a trigger, which might invoke multiple threads to update this variable, however the update should happen only once by the first thread whichever arrives at the critical section.

理想情况下,流程应如下所示:

Ideally the flow should be like follows:

线程-1;调用Thread-2和Thread-3更新关键部分中由锁或互斥锁保护的变量

Thread-1; Thread-2 and Thread-3 are invoked to update a variable in critical section guarded by a lock or a mutex

使用此防护的关键部分仅允许一个线程进入,线程2和线程3仅在外部等待.

Critical section using this guard allows only one thread to enter, Thread-2 and Thread-3 wait just outside.

一旦线程1更新了此变量;线程2和线程3在不影响变量的情况下继续执行其他工作.

Once this variable is updated by Thread-1; Thread-2 and Thread-3 resume with other work without causing an effect on the variable.

我想出了以下实现,但是我无法让其他线程等待并跳过更新:

I have come up with the following implementation, but I am not able to make other threads wait and skip updation:

public class Main {


    private static ReentrantLock lock = new ReentrantLock();
    private int counter = 0;

    public static void main(String[] args) {
        Main m = new Main();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();


    }


    private void doSomeOperation() {

    try {
        System.out.println("Thread about to acquire lock: " + Thread.currentThread().getName());
        if (lock.tryLock()) {
            System.out.println("Lock held by " + Thread.currentThread().getName() + " " + lock.isHeldByCurrentThread());
            counter++;
            // Thread.sleep(3000);
            System.out.println("Counter value: " + counter + " worked by thread " + Thread.currentThread().getName());
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
            System.out.println("Unlocked: " + Thread.currentThread().getName());
        }
    }


}
}

最后,计数器值是3,我希望计数器值也是一个,也希望其他线程等待第一个线程更新计数器.想法表示赞赏.我宁愿使用锁/互斥锁而不是等待通知的解决方案.

At the end, the counter value is 3, I want counter value to be one also I want other threads to wait till the first thread updates the counter. Ideas appreciated. I would prefer a solution using locks / mutex rather than wait and notify.

输出:

Thread about to acquire lock: Thread-0
Lock held by Thread-0 true
Thread about to acquire lock: Thread-1
Counter value: 1 worked by thread Thread-0
Unlocked: Thread-0
Thread about to acquire lock: Thread-2
Lock held by Thread-2 true
Counter value: 2 worked by thread Thread-2
Unlocked: Thread-2

Process finished with exit code 0

注意我的用例是不同的-为了简化起见,更新计数器的示例.实际上,我正在doSomeOperation方法中更新会话令牌.

推荐答案

出现问题是因为最初一个线程增加了计数器并释放了锁,并且您的程序运行得如此之快,以至于一旦第一个线程释放了锁,然后另一个线程进入了该方法并看到无锁,因此它获取了锁并进一步增加了计数器.在这种情况下,您可以使用 countDownLatch .

Problem is occurring because Initially one thread increases the counter and release the lock and your program is running so fast that, once first thread releases the lock then another thread enters the method and it sees the lock free so it acquires the lock and increase the counter further. You can make use of countDownLatch in this case.

这里得到锁的一个线程将锁存器计数减少一并使其为零,此后,由于该线程没有一个能够处理,因此 latch.getCount()== 1 条件将失败.

Here one thread which get the lock decrease the latch count by one and makes it zero, after that none of the thread will be able to process because latch.getCount()==1 condition will fail.

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

public class Test2 {


    private static ReentrantLock lock = new ReentrantLock();
    private static CountDownLatch latch= new CountDownLatch(1);
    private int counter = 0;

    public static void main(String[] args) {
        Test2 m = new Test2();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();


    }


    private void doSomeOperation() {

    try {
        System.out.println("Thread about to acquire lock: " + Thread.currentThread().getName());
        if (lock.tryLock() && latch.getCount()==1) {
            System.out.println("Lock held by " + Thread.currentThread().getName() + " " + lock.isHeldByCurrentThread());
            counter++;
            latch.countDown();
             Thread.sleep(3000);
            System.out.println("Counter value: " + counter + " worked by thread " + Thread.currentThread().getName());
            }
        System.out.println("Exiting" + Thread.currentThread().getName());

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
            System.out.println("Unlocked: " + Thread.currentThread().getName());
        }
    }


}
}
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

public class Test2 {


    private static ReentrantLock lock = new ReentrantLock();
    private static CountDownLatch latch= new CountDownLatch(1);
    private int counter = 0;

    public static void main(String[] args) {
        Test2 m = new Test2();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();

        new Thread(m::doSomeOperation).start();


    }


    private void doSomeOperation() {

    try {
        System.out.println("Thread about to acquire lock: " + Thread.currentThread().getName());
        if (lock.tryLock() && latch.getCount()==1) {
            System.out.println("Lock held by " + Thread.currentThread().getName() + " " + lock.isHeldByCurrentThread());
            counter++;
            latch.countDown();
             Thread.sleep(3000);
            System.out.println("Counter value: " + counter + " worked by thread " + Thread.currentThread().getName());
            }
        System.out.println("Exiting" + Thread.currentThread().getName());

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
            System.out.println("Unlocked: " + Thread.currentThread().getName());
        }
    }


}
}

这篇关于Java-允许一个线程更新值,其他线程等待和跳过关键部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆