线程之间的不公平同步

发布于 2025-01-13 10:23:38 字数 2591 浏览 2 评论 0原文

我有这样的代码模式:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

public class TestRunner {
    public static final Object lockObject = new Object();

    public static final AtomicInteger counter1 = new AtomicInteger();
    public static final AtomicInteger counter2 = new AtomicInteger();

    public static class Runner1 implements Runnable {
        private volatile boolean running = true;
        @Override
        public void run() {
            while (running) {
                synchronized (lockObject) {
                    counter1.getAndIncrement();
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {

                    }
                }
                // Thread.yield();
            }
        }

        public void stop() {
            running = false;
        }
    }

    public static class Runner2 extends TimerTask {
        @Override
        public void run() {
                synchronized (lockObject) {
                    counter2.getAndIncrement();
                }
        }
    }

    public static void main(String[] args) throws Exception {
        Runner1 runner1 = new Runner1();
        Runner2 runner2 = new Runner2();

        Thread thread1 = new Thread(runner1);
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(runner2, 0, 10);

        thread1.start();

        Thread.sleep(10000);
        timer.cancel();
        runner1.stop();

        int runner1Percent = (counter1.get()*100 /(counter1.get()+counter2.get()));
        System.out.println("No of times Runner1 got called: " + counter1.get());
        System.out.println("No of times Runner2 got called: " + counter2.get());
        System.out.println("Percentage Runner1 acquire the lock: " + runner1Percent);
        System.out.println("Percentage Runner2 acquire the lock: " + (100-runner1Percent));
    }
}

我运行此代码大约 10 秒,这是输出:

No of times Runner1 got called: 877 
No of times Runner2 got called: 10 
Percentage Runner1 acquire the lock: 98 
Percentage Runner2 acquire the lock: 2

如此处所示,Thread1 能够获取 98% 的锁,而计时器仅 能够获取锁2%。

如果我取消注释 Thread.yield() 语句并重新运行它,输出 显示:

No of times Runner1 got called: 858
No of times Runner2 got called: 1001
Percentage Runner1 acquire the lock: 46
Percentage Runner2 acquire the lock: 54

这表明Thread1和Timer更均匀地共享锁。这是否意味着 jvm 有一些优化/缓存,以便 Thread1 能够继续获取锁?如果由于其他一些限制我无法替换同步块,那么 Thread.yield() 是否是让线程更均匀地共享锁的正确方法?

任何建议都会有帮助。

I have a code pattern like this:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

public class TestRunner {
    public static final Object lockObject = new Object();

    public static final AtomicInteger counter1 = new AtomicInteger();
    public static final AtomicInteger counter2 = new AtomicInteger();

    public static class Runner1 implements Runnable {
        private volatile boolean running = true;
        @Override
        public void run() {
            while (running) {
                synchronized (lockObject) {
                    counter1.getAndIncrement();
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {

                    }
                }
                // Thread.yield();
            }
        }

        public void stop() {
            running = false;
        }
    }

    public static class Runner2 extends TimerTask {
        @Override
        public void run() {
                synchronized (lockObject) {
                    counter2.getAndIncrement();
                }
        }
    }

    public static void main(String[] args) throws Exception {
        Runner1 runner1 = new Runner1();
        Runner2 runner2 = new Runner2();

        Thread thread1 = new Thread(runner1);
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(runner2, 0, 10);

        thread1.start();

        Thread.sleep(10000);
        timer.cancel();
        runner1.stop();

        int runner1Percent = (counter1.get()*100 /(counter1.get()+counter2.get()));
        System.out.println("No of times Runner1 got called: " + counter1.get());
        System.out.println("No of times Runner2 got called: " + counter2.get());
        System.out.println("Percentage Runner1 acquire the lock: " + runner1Percent);
        System.out.println("Percentage Runner2 acquire the lock: " + (100-runner1Percent));
    }
}

I run this code for about 10 second and here is the output:

No of times Runner1 got called: 877 
No of times Runner2 got called: 10 
Percentage Runner1 acquire the lock: 98 
Percentage Runner2 acquire the lock: 2

As indicated here, Thread1, is able to acquire the lock 98% while the timer, is only
able to acquire the lock 2%.

If I uncomment out the Thread.yield() statement and rerun it, the output
shows:

No of times Runner1 got called: 858
No of times Runner2 got called: 1001
Percentage Runner1 acquire the lock: 46
Percentage Runner2 acquire the lock: 54

This shows that Thread1 and Timer share the lock more uniformly. Does this mean the jvm has some optimization/caching so that Thread1 is able to keep acquiring the lock? If I am not able to replace the synchronized block due to some other restrictions, is Thread.yield() a right approach to have the threads sharing the lock more uniformly?

Any suggestions would be helpful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文