gpt4 book ai didi

java - RMI自动为 "thread safe"吗?

转载 作者:行者123 更新时间:2023-12-01 16:50:30 24 4
gpt4 key购买 nike

我正在学习如何使用 Java RMI 来编写分布式应用程序。我编写了一个简单的程序只是为了测试一些东西,我只是通过客户端向服务器提供整数,然后服务器将它们累积在静态变量中。这是代码:

服务器:

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");

}

}

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

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

但是,为了看看会发生什么,我删除了该 block ,并且我仍然始终得到正确的结果(值为 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 中绑定(bind)一个对象时,我到底绑定(bind)了什么?我调用 Naming.rebind() 的对象的特定实例,或者类(然后当我查找它时,我只是得到一个新实例?)?

最佳答案

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

此外,您正在绑定(bind) Sommatore 的实例,但正在显示 Adder 的代码。

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

关于java - RMI自动为 "thread safe"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41050155/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com