繁体   English   中英

两个线程中的公共数据

[英]common data in two threads

我想要两个线程。 一个会增加我的变量,另一个会在变量增加后立即将其显示在屏幕上。

我想使用wait()notifyAll()函数来执行此操作,但是我遇到了一些问题。

我已经编写了这段代码,但是它在某些时候停止工作(它只显示第一个和最后一个数字:1和10)。

public class TestClass {
    static int x = 0;
    public static Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    for(int i = 0; i < 10; i++) {
                        synchronized (lock) {
                            lock.wait();
                            System.out.println(x);
                        }
                    }
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }           
            }
        });
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            public void  run() {
                for(int i = 0; i < 10; i++) {
                    synchronized (lock) {
                        x++;
                        lock.notifyAll();
                    }
                }
            }
        });
        t2.start();
    }
}

我试图增加额外notifyAll()中的第一个线程和wait()在第二个( t2 ),但它仍然无法正常工作。 我该怎么做呢?

JavaDoc

在当前线程放弃该对象上的锁之前,唤醒的线程将无法继续。 唤醒的线程将以通常的方式与可能正在主动竞争以在此对象上进行同步的任何其他线程竞争。 例如,被唤醒的线程在成为锁定该对象的下一个线程时没有任何可靠的特权或劣势。

您刚醒来的线程并不能保证立即获得该锁,因此您可以让调用notifyAll()的循环在其他线程被唤醒之前运行其所有迭代。

如果您希望他们轮换,一种方法是轮流等待

以下是一个可行的解决方案。 关键是添加一个附加标志,该标志将指示写入线程是否有权写入。 在锁对象上注意final ,这是一个好习惯。

public class TestClass
{
    private static int x = 0;
    private static final Object lock = new Object();  
    private static boolean canWrite = false;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    for(int i = 0; i < 10; i++)
                    {  
                        synchronized(lock)
                        {                            
                            if(!canWrite)                            
                                lock.wait();
                            System.out.println(x);
                            canWrite = false;
                            lock.notify();
                        }
                    }                    
                } 
                catch (InterruptedException e) {}
            }
        });        

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    for(int i = 0; i < 10; i++)
                    {                                                
                        synchronized(lock)
                        {                                                              
                            x++;
                            canWrite = true;
                            lock.notify();
                            lock.wait();
                        }
                    }                            
                } catch (InterruptedException ex) {}                                                                        
            }
        });
        t1.start();        
        t2.start();
    }
}

该模式令人困惑,但是如果您想尝试控制线程,我想这是一个有用的练习。

更改您的代码以给您的线程起一个好名字,例如“ test1”和“ test2”。 运行您的程序并为其挖掘进程ID,然后运行

jstack <pid>

(您可以在JDK的bin目录中找到它)。 这是(也许)您将看到的内容: test1将等待一个

lock.wait();

test2将等待

lock.wait();

也一样

从第一次迭代开始。 test2获胜并调用notify,这根本没有任何效果,因为没有什么等待锁。 然后test2开始等待。 现在test1可以进入并立即进入等待状态。

如果test1第一次获胜,那么您可以进入一个似乎有效的周期。

这就是为什么您获得第一个数字( test2优先)或最后一个数字( test1优先)的原因。

那几乎就是我的样子,但是您的jstack肯定会告诉您。 PS:通常使用CountDownLatch和并发包。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM