java:将类引用传递给另一个线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17940115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 19:40:37  来源:igfitidea点击:

java: Passing a class reference to another thread

javamultithreading

提问by dman33

I'm trying to learn how to use multithreading in Java. I have a main and two classes which extend Thread, A and B. I want the main to start A, which makes multiple calls to B. Once A is finished, I want B to send something to main.

我正在尝试学习如何在 Java 中使用多线程。我有一个 main 和两个扩展 Thread 的类,A 和 B。我希望 main 启动 A,它对 B 进行多次调用。一旦 A 完成,我希望 B 向 main 发送一些东西。

The main creates two threads, one A and one B, and then starts both threads. A does something, which will then pass on a result to B. The main then collects an answer from B and does something else. I don't know how to get the total from B back to the main.

main 创建了两个线程,一个 A 和一个 B,然后启动两个线程。A 做某事,然后将结果传递给 B。然后主要从 B 收集答案并做其他事情。我不知道如何将总数从 B 返回到主要。

I'm also not sure how to instantiate the two classes (threads) but then give A a reference of B since Java uses pass-by-value. Can someone give me some pointers.

我也不确定如何实例化这两个类(线程),但由于 Java 使用按值传递,因此给 A 一个 B 的引用。有人可以给我一些指点。

public static void main(String[] args)
{
    B b = new B();
    A a = new A(100, b);

    B.start();
    A.start();

    A.join(); // Waiting for A to die

    // Here I want to get a total from B, but I'm not sure how to go about doing that

}


public class A extends Thread
{
    private int start;
    // Some reference to B
    B b;
    public A (int n, B b) {
        int start = n;
        this.b = b;
    }

    public void run() {
        for (int i = 0; i < n; i++) {
            b.add(i);
        }
    }
}

public class B extends Thread
{
    private int total;

    public B () {
        total = 0;
    }

    public void add(int i) {
        total += i;
    }
}

回答by uhre

I changed your example code into what I consider to be a more meaningful example.

我将您的示例代码更改为我认为更有意义的示例。

Communication between threads is usually handled through shared data (or channels like pipes, sockets - but I wont go there...). And while it is perfectly alright to have this shared data contained within the thread classes I have seperated the shared data from the data/methods used to administer the threads.

线程之间的通信通常通过共享数据(或管道、套接字之类的通道 - 但我不会去那里......)进行处理。虽然将这些共享数据包含在线程类中是完全正确的,但我已经将共享数据与用于管理线程的数据/方法分开了。

I hope this helps you to understand the relationship between threads and data objects.

我希望这有助于您理解线程和数据对象之间的关系。

public class TestThreads {
    public static void main(String[] args)
    {
        DataShare ds = new DataShare();
        B b = new B(ds);
        A a = new A(100, ds);

        b.start();
        a.start();

        try {
            a.join(); // Waiting for A to die
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println ("Accumulated total from B = " + b.getTotal());      
        b.endThread();
    }   
}


public class DataShare {
    private int value;

    public DataShare () {
        value = -1;
    }

    public synchronized boolean setValue(int val) {
        boolean valueSet = false;
        if (value == -1) {
            value = val;
            valueSet = true;
        }
        return valueSet;        
    }

    public synchronized int getValue() {
        int val = value;
        value = -1;
        return val;
    }    
}


public class A extends Thread {
    private int max;
    private DataShare dataShare;

    public A (int n, DataShare ds) {
        max = n;
        dataShare = ds;
    }

    public void run() {
        int i = 0;
        while (i < max) {
            if (dataShare.setValue(i)) {
                i++;
            }
        }
    }
}


public class B extends Thread {
    private int total;
    private DataShare dataShare;
    private boolean running = false;

    public B (DataShare ds) {
        dataShare = ds;
        total = 0;
    }

    public void run() {
        running = true;
        while (running) {
            int nextValue = dataShare.getValue();
            if (nextValue != -1) {
                total += nextValue;
            }
        }
    }

    public int getTotal() {
        return total;
    }

    public synchronized void endThread() {
        running = false;
    }
}

I am aware that this naive example is far from optimal since both threads are wasting precious cycles while waiting for the value to be set/read. I just wanted to keep the example as simple as possible while still addressing the point I'm trying to make.

我知道这个简单的例子远非最佳,因为两个线程在等待设置/读取值时都在浪费宝贵的周期。我只是想让这个例子尽可能简单,同时仍然解决我试图提出的观点。

回答by Ghostman

A decent way to do it. You just pass an instanceof class A:

一个体面的方法来做到这一点。您只需传递A 类的实例

public class Foo {
   public void doFoo() {..} // that's the method you want to use
}

public class Bar {
   private Foo foo;
   public Bar(Foo foo) {
      this.foo = foo;
   }

   public void doSomething() {
      foo.doFoo(); // here you are using it.
   }
}

And then you can have:

然后你可以有:

Foo foo = new Foo();
Bar bar = new Bar(foo);
bar.doSomething();

回答by tbodt

First of all, B should not be a thread. If all it does is respond to messages from A, then it can just be an object like any other.

首先,B不应该是线程。如果它所做的只是响应来自 A 的消息,那么它可以像任何其他对象一样只是一个对象。

Second, while everyone says java uses pass by value, the confusing part is that object references are passed by value, so objects are effectively passed by reference. Thus, you can pass B to A, and get the total from your copy of B.

其次,虽然大家都说java使用按值传递,但令人困惑的部分是对象引用是按值传递的,因此对象实际上是按引用传递的。因此,您可以将 B 传递给 A,并从 B 的副本中获取总数。

回答by bas

If we look at your code:

如果我们查看您的代码:

B b = new B();
A a = new A(100, b);

B.start();
A.start();

A.join(); // Waiting for A to die

// Here I want to get a total from B, but I'm not sure how to go about doing that

You are passing a pointer of bto A. That means that if class Aonly accesses class Bdirectly (it does not replace it with a newinstance of B) that the object should contain anything that class Adid to it. In other words, both your main code and class Awork on the same object of B. So you should be able to get the total of bsimply by asking the object you have instantiated in main.

您正在传递bto的指针A。这意味着如果class Aclass B直接访问(它不会用newB的实例替换它),对象应该包含class A对它所做的任何事情。换句话说,无论你的主代码和class A工作的同一对象上B。因此,您应该能够b通过询问您在 中实例化的对象来获得总数main

So if you call

所以如果你打电话

b.total();

at the end of main, it should return your value (of course you must ensure that thread A will not make changes to it after retrieving the value).

在 main 的末尾,它应该返回您的值(当然您必须确保线程 A 在检索值后不会对其进行更改)。

回答by uhre

I assume that you are trying to achieve communication between the two threads you create in the main method. This is, however, not happening. I made a few changes to your code and included it below to show what I think you wanted to do.

我假设您正在尝试实现在 main 方法中创建的两个线程之间的通信。然而,这并没有发生。我对您的代码进行了一些更改并将其包含在下面以显示我认为您想要做什么。

First, a few corrections of your examples:

首先,对您的示例进行一些更正:

You cannot use class names (A and B) when referencing thread objects as you do in the main method. Use the object names instead (a and b).

在引用线程对象时,不能像在 main 方法中那样使用类名(A 和 B)。改用对象名称(a 和 b)。

In class A constructor you are creating a new local variable startinstead of referencing the member variable. Hence: int start = nshould be start = n

在类 A 构造函数中,您正在创建一个新的局部变量start而不是引用成员变量。因此:int start = n应该是start = n

I'm guessing you want to loop the number of times set in constructor. Hence for (int i = 0; i < n; i++) {should be for (int i = 0; i < start; i++) {

我猜你想循环构造函数中设置的次数。因此for (int i = 0; i < n; i++) {应该是for (int i = 0; i < start; i++) {

Pass by reference/value is not really relevant here. Object references are passed by value as anything else is. It is, however, the contents of the reference variable (the object address) which is interesting and that will not change. In other words, when passing an object reference to a method, the method WILL address that specific object, and any change made to the contents of the objects will be visible outside the method as well.

通过引用/值传递在这里并不真正相关。对象引用按值传递,就像其他任何东西一样。然而,有趣的是引用变量(对象地址)的内容并且不会改变。换句话说,当将对象引用传递给方法时,该方法将寻址该特定对象,并且对对象内容所做的任何更改也将在该方法之外可见。

Here are your examples with a few corrections as I think you intended them.

这是您的示例,其中有一些更正,因为我认为您打算这样做。

public class TestThreads {
        public static void main(String[] args)
        {
            B b = new B();
            A a = new A(100, b);

            b.start();
            a.start();

            try {
                a.join(); // Waiting for A to die
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // Getting a total from b is simple, if you provide the method for it
                System.out.println ("Accumulated total from B = " + b.getTotal());      
        }

}


public class A extends Thread {
    private int start;
    // Some reference to B
    B b;
    public A (int n, B b) {
        start = n;
        this.b = b;
    }

    public void run() {
        for (int i = 0; i < start; i++) {
            b.add(i);
        }
    }
}


public class B extends Thread {
    private int total;

    public B () {
        total = 0;
    }

    public void add(int i) {
        total += i;
    }

    public int getTotal() {
        return total;
    }
}

Now, here is the problem with these examples:

现在,这是这些示例的问题:

An object is not a thread and vice versa. In the main thread (lets call that thread tM) You are creating an object of class B and forking a new thread (thread tB) starting in its run() method. However, since you did not override the run method, the threat ends immediately after creation.

对象不是线程,反之亦然。在主线程中(让我们调用该线程 tM)您正在创建一个类 B 的对象并从其 run() 方法开始分叉一个新线程(线程 tB)。但是,由于您没有覆盖 run 方法,因此威胁在创建后立即结束。

Then you create an object of class A. Gives it the reference to object b (which has nothing to do with thread tB) and fork a new thread (thread tA). Here you did implement a run() method. The result is the following:

然后你创建一个类 A 的对象。给它对象 b 的引用(它与线程 tB 无关)并派生一个新线程(线程 tA)。在这里,您确实实现了一个 run() 方法。结果如下:

Thread tM did the initial work and is now waiting for thread tA to finish. Thread tB was started and died immediately afterwards Thread tA is doing all the work of incrementing the counter of object a, and making object b add the counter to its sum.

线程 tM 完成了初始工作,现在正在等待线程 tA 完成。线程 tB 启动并在之后立即死亡线程 tA 正在执行所有增加对象 a 的计数器的工作,并使对象 b 将计数器添加到其总和中。

When tA finished after 100 increments tM wakes up and acquires the sum from object b (which again has nothing to do with thread tB).

当 tA 在 100 次增量后完成时,tM 唤醒并从对象 b 获取总和(这又与线程 tB 无关)。