Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java RMI是否自动执行;线程安全;?_Java_Multithreading_Thread Safety_Rmi - Fatal编程技术网

Java RMI是否自动执行;线程安全;?

Java RMI是否自动执行;线程安全;?,java,multithreading,thread-safety,rmi,Java,Multithreading,Thread Safety,Rmi,我正在学习如何使用JavaRMI来编写分布式应用程序。 我写了一个简单的程序来测试一些东西,我只是通过一个客户端给服务器一个整数,服务器将它们累加到一个静态变量中。代码如下: 服务器: public class Adder extends UnicastRemoteObject implements IAdder { /** * */ private static final long serialVersionUID = 8229278619948724254L; private st

我正在学习如何使用JavaRMI来编写分布式应用程序。 我写了一个简单的程序来测试一些东西,我只是通过一个客户端给服务器一个整数,服务器将它们累加到一个静态变量中。代码如下:

服务器:

public class Adder extends UnicastRemoteObject implements IAdder {

/**
 * 
 */
private static final long serialVersionUID = 8229278619948724254L;
private static Integer sum = 0; 
static Logger logger = Logger.getLogger("global");

protected Adder() throws RemoteException {
    super();
    // TODO Auto-generated constructor stub
}

@Override
public void add(int i) throws RemoteException {
    System.out.println("Got: " + i);
    synchronized (sum) {
        sum += i;
        System.out.println("The new sum is: " + sum);
    }
}

@Override
public int result() throws RemoteException {
    System.out.println("The sum is: " + sum);
    return sum;
}


public static void main(String[] args) {
    System.setSecurityManager(new SecurityManager());
    try  {
        logger.info("Building remote object");
        Adder obj = new Adder();
        logger.info("Binding");
        Naming.rebind("SommaServer", obj);
        logger.info("Ready");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}
客户:

public class Client extends Thread {

static Logger logger = Logger.getLogger("global");
private IAdder obj;
private int array[] = new int[3];

public static void main(String[] args) {
    try {
        Client c1 = new Client(1);
        Client c2 = new Client(2);
        c1.start();
        c2.start();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void work(int i) throws RemoteException {
    obj.add(i);
}

public void run()  {
    Random rn = new Random();
    try {
        work(array[0]);
        work(array[1]);
        work(array[2]);
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public Client(int i) throws Exception {
    if (i == 1) {
        array[0] = 1;
        array[1] = 3;
        array[2] = 4;
    }
    if (i == 2) {
        array[0] = 7;
        array[1] = 2;
        array[2] = 5;
    }
    logger.info("Remote object lookup");
    obj = (IAdder) Naming.lookup("rmi://localhost/SommaServer");

}

}
在客户端的主要部分,我创建了两个客户端线程,并运行它们(我知道没有同步性检查,但我只是尝试一下)。每个线程都有一个数字数组要提供给服务器。 服务器接收它们,然后将它们全部添加到一起

因此,由于我处理的是线程,我的第一个想法是,我需要在总和的更新上使用锁,否则我可能会因为线程的交错而出错。因此,服务器中的同步块

但是,为了看看会发生什么,我删除了块,我仍然得到了正确的结果,所有的时间(值是22)

为了确保我也制作了一个“本地”版本的客户端,它更新了一个本地变量:

public class Client extends Thread {
private static Integer sum = 0;
static Logger logger = Logger.getLogger("global");
private IAdder obj;
private int array[] = new int[3];

public static void main(String[] args) {
    try {
        Client c1 = new Client(1);
        Client c2 = new Client(2);
        c1.start();
        c2.start();
        c1.join();
        c2.join();
        System.out.println("Ricevuto: " + sum);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void work(int i) throws RemoteException {
    //obj.add(i);
    synchronized(sum) {
        sum += i;
    }
}

public void run()  {
    Random rn = new Random();
    try {
        work(array[0]);
        work(array[1]);
        work(array[2]);
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public Client(int i) throws Exception {
    if (i == 1) {
        array[0] = 1;
        array[1] = 3;
        array[2] = 4;
    }
    if (i == 2) {
        array[0] = 7;
        array[1] = 2;
        array[2] = 5;
    }
}

}
有了同步,我得到了正确的结果,没有同步,我得到了各种数字(8,15,14,22…)

那么,到底发生了什么?我怀疑RMI是否能像那样保证线程安全


额外问题:当我在RMI中绑定一个对象时,我到底绑定了什么?我调用Naming.rebind()的对象的特定实例,或者该类(然后当我查找它时,我只得到一个新实例?)

您的同步已中断,因此您无法通过实验推断出多少。每次执行
sum+=i
,都会为
sum
分配一个新的整数。因此线程在两个不同的整数上同步

另外,您正在绑定Sommatore的一个实例,但是您正在显示加法器的代码


但为了回答您的问题,您正在绑定一个实例,RMI不会神奇地创建该实例的副本。它也不会同步对此实例的所有调用。因此,您需要确保代码是线程安全的。尽管没有适当的同步,但快速测试仍然会产生正确的结果,这并不意味着它总是这样。你可以闭着眼睛过十次马路,永远不会死。这并不意味着它是安全的。

你的同步被破坏了,所以你不能通过实验推断出多少。每次执行
sum+=i
,都会为
sum
分配一个新的整数。因此线程在两个不同的整数上同步

另外,您正在绑定Sommatore的一个实例,但是您正在显示加法器的代码

但为了回答您的问题,您正在绑定一个实例,RMI不会神奇地创建该实例的副本。它也不会同步对此实例的所有调用。因此,您需要确保代码是线程安全的。尽管没有适当的同步,但快速测试仍然会产生正确的结果,这并不意味着它总是这样。你可以闭着眼睛过十次马路,永远不会死。这并不意味着它是安全的

RMI是否自动“线程安全”

没有

额外问题:当我在RMI中绑定一个对象时,我到底绑定了什么?我调用的Naming.rebind()对象的特定实例,或者该类(然后当我查找它时,我只会得到一个新实例?)

实际上两者都不是。您正在绑定一个存根,它与您提供给
bind()
方法的远程对象实例不可恢复地关联

RMI是否自动“线程安全”

没有

额外问题:当我在RMI中绑定一个对象时,我到底绑定了什么?我调用的Naming.rebind()对象的特定实例,或者该类(然后当我查找它时,我只会得到一个新实例?)


实际上两者都不是。您正在绑定一个存根,它与您提供给
bind()
方法的远程对象实例存在不可恢复的关联。

没有找到,我修复了它!我的意思是,这就是我的观点,如果没有同步(我已经修复了,谢谢),它应该不会正常工作?我应该补充一点,即使对服务器的调用是无序的,最终的结果是正确的,就好像文字是同步的,这让我很反感。同样,逻辑是有缺陷的。它在没有同步的简单测试中运行良好并不意味着“它是线程安全的”。这仅仅意味着你还没有找到让它失败的方法。从许多不同的线程,在多个进程中运行,调用服务器数百万次,而不仅仅是3次,您可能会看到失败。一个例子足以证明它不是线程安全的。为了证明它是线程安全的,一个例子远远不够。就像闭着眼睛过马路并活着并不能证明闭着眼睛过马路是安全的。当然,你是对的。我尝试了10000次循环客户端,但是没有同步,它就不能正常工作。只是我已经习惯了这样的事情,在尝试了几次之后失败了,但这给出了正确的答案,即使尝试了更多,所以我很困惑。错过了,我修复了它!我的意思是,这就是我的观点,如果没有同步(我已经修复了,谢谢),它应该不会正常工作?我应该补充一点,即使对服务器的调用是无序的,最终的结果是正确的,就好像文字是同步的,这让我很反感。同样,逻辑是有缺陷的。它在没有同步的简单测试中运行良好并不意味着“它是线程安全的”。这仅仅意味着你还没有找到让它失败的方法。从许多不同的线程,在多个进程中运行,调用服务器数百万次,而不仅仅是3次,您可能会看到失败。一个例子足以证明它不是线程安全的。为了证明它是线程安全的,一个例子远远不够。就像闭着眼睛过马路并活着并不能证明闭着眼睛过马路是安全的。当然,你是对的。我尝试了10000次循环客户端