【问题标题】:Fork and join concept lagging分叉和连接概念滞后
【发布时间】:2017-12-14 14:28:26
【问题描述】:

这是一个示例代码,我写这个只是为了让你理解我写在下面的问题。 这是一个类,它有一个示例方法,可以为不同的 a 计算一些值;

public class Class1{
public int examplemethod(int a){
     int k = a*2;
     int b=k+1;
     ......some more manipulation 
     return k;
}
}

下面的类会并行调用上面的方法

public class Class2 extends RecursiveTask<Integer>{
int a=0;
Class1 obj; 
public Class2(int a, Class1 obj){
     this.a = a;
     this.obj=obj;
}  
@Override
protected Integer compute () {
     return obj.examplemethod(a); 
 } 


public static void main(Strings[] args){
   List<Class2> list =new ArrayList<Class2>(); 
   Class1 obj = new Class1();
    for(int i=4;i<7;i++){
       Class2 obj2=new Class2(obj);
       obj2.fork();
       list.add(obj2);
    }
    int arr[]=new int[4];
     int i=0;
    if(list.size>0){
       for(Class2 ob:list){
            arr[i++]= ob.join();
       } 

    }

}
}

我在 for 循环中创建了 class2 的三个对象,因此假设第一个 fork 将使用 a=4 计算值,但是当它在 examplemethod 中计算时,cpu 调度另一个线程让我们说 fork 2 使用 a=5 并保存程序fork 1 线程的计数器,现在在使用 a=5 计算值时,它会更改 examplemethod 中的一些变量,而这些变量之前是由 fork1 更改的,所以现在我的问题是,如果 examplemethod 是在该类的所有对象之间共享的资源,并且如果一个对象在函数中做了一些更改,在中间(线程切换)一些其他对象出现并更改了相同的变量,然后我的输出会受到影响,但问题是我得到了正确的答案,所以我的概念在并行线程中滞后,线程将共享一个公共资源,所以我的代码中的关键部分在哪里。

【问题讨论】:

  • (1) 请遵守名称约定,让每个人都更容易使用——特别是,类名应该是驼峰式,首字母大写。 (2) 您的代码无效。它的问题之一是它为类class2 调用了一个无参数构造函数,但该类没有这样的构造函数,并且它试图使用原始类型int 作为类型参数。这不是一份详尽的清单。
  • b=x; -- 什么是b?如果该陈述是相关的,那么您已经省略了重要的细节;如果没有,请不要包含它。此外,一个非常长的连续句子非常难以破译。如果您需要帮助,请让其他人更容易理解您的问题。此外,RecursiveTask&lt;int&gt; 不是有效的 Java。请包含可编译的代码。
  • 我做了一些更改,请删除标记它的 -1,如果您仍然想要一些更改,我可以这样做,我没有提供我的实际代码我只是正确的示例 pseduo,以便我的问题可以是可以理解。
  • 在文档中有一个关于如何使用RecursiveTask的最小示例。
  • 一个类构造函数没有void返回类型,进一步它必须区分大小写匹配类名,即public Class2(int a) { this.a = a; } 此外,你必须在构造对象时指定适当的参数, new Class2(i).

标签: java multithreading java-8 operating-system


【解决方案1】:

在方法中声明的变量是局部变量,具有特定方法调用的特定值。您应该首先独立于多线程方面来理解该概念。例如。以下程序将打印什么:

public class Test {
    public static void main(String[] args) {
        test(5);
    }

    private static void test(int i) {
        System.out.println("enter test with "+i);
        if(i>0) test(i-1);
        System.out.println("leave test with "+i);
    }
}

当多个线程执行相同的方法时,这些变量的局部性质不会改变。这些执行之间没有干扰。

同样,实例变量,即在没有static 修饰符的类中声明的成员变量。保存特定对象实例的特定值,因此,如果您创建多个实例,它们可以为这些变量具有不同的值,而不会相互影响。

这些是用于构建多线程程序而不需要一直进行线程同步的构建块。如果您创建表示要执行的不同任务的不同对象,并且这些任务仅使用这些对象和/或其方法参数(方法参数是局部变量)执行方法来计算结果,则这些任务已经被隔离了。

不能做的事情是修改static变量或共享对象的实例变量。在您的代码中,没有共享对象。

【讨论】:

  • 所以如果我共享一个对象 b/w 线程并计算值,那么我需要使用同步吗?我已经更新了代码,请看
  • 关键方面是共享状态的修改。在您的代码中,Class1 没有实例变量,因此examplemethod 无法修改它们。如果Class1 有实例变量并且examplemethod 正在修改它们,则必须使用线程安全构造,例如将examplemethod 声明为synchronized。然后,您必须决定修改是否适合语义,因为您无法控制任务调用该方法的顺序。
【解决方案2】:

您的代码中的线程之间共享哪些资源?

简而言之,您的class1 是线程安全的,因为在方法内部定义的变量不能被另一个线程更改。

虽然 class2 不是 - 当且仅当两个线程可以同时使用 class2 的相同实例(又名 Singleton)并且线程更改了一些实例变量,而另一个线程使用它。

class2 - int a 中只有一个实例变量。

但在代码中我没有看到任何类型的 Singleton 或实例变量 "a"change...

每个线程都有一个新的 class2 实例:Class2 obj2=new Class2();

(实际上一定是Class2 obj2=new Class2(aValue);

我错过了什么吗?

【讨论】:

    猜你喜欢
    • 2011-04-24
    • 1970-01-01
    • 2012-01-15
    • 2017-05-21
    • 2012-02-06
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    相关资源
    最近更新 更多