静态变量、线程和Java构造函数
我从一本公认的样本书中看到了这一点,所以很难提出问题,然后我就不明白了 一个名为DataflightsService的类包含一个名为FlightFileAccess的私有静态变量,每当我们在构造函数中创建DataflightsService的新对象作为FlightFileAccess的初始化时,该变量都会被实例化 即静态变量、线程和Java构造函数,java,multithreading,variables,static,Java,Multithreading,Variables,Static,我从一本公认的样本书中看到了这一点,所以很难提出问题,然后我就不明白了 一个名为DataflightsService的类包含一个名为FlightFileAccess的私有静态变量,每当我们在构造函数中创建DataflightsService的新对象作为FlightFileAccess的初始化时,该变量都会被实例化 即 对我来说,这意味着每次创建dataflightssservice的实例时,构造函数中的静态变量FlightFileAccess 在原始的FlightFileAccess类中:我们
对我来说,这意味着每次创建
dataflightssservice
的实例时,构造函数中的静态变量FlightFileAccess
在原始的FlightFileAccess
类中:我们有一个remove方法来同步RandomAccessFile
因此,因为我们使用了不同的FlightFileAccess
引用,所以我们也使用了不同的RandomAccessFile
引用
这意味着将FlightFileAccess
作为静态服务在这里并不用于RandomAccessFile
上的同步,因为它每次都是新的,所以每个DataflightsService
实例将在随机访问文件上执行它们的操作,而忽略同步。
与在静态启动器中实例化FlightFileAccess
相反。我说得对吗
我希望能提供尽可能多的解释,以提供最好的方式,尽可能多地实例化DataflightsService
(假设每个客户端都有自己的DataflightsService
)在这之后,您可以同步一个文件以进行删除,例如,这样就不会出现多个客户端访问该文件的混乱情况。很抱歉,我需要为每个客户端包含一个DataflightsService
,因为没有Cookie。您的示例将无法编译,因为构造函数的名称与类不匹配。但是,如果您想命名构造函数public DataflightsService()
,那么问题的一部分在于每次创建新对象时都会覆盖静态变量
听起来您希望这个静态变量只初始化一次。通常,您只需使用private static final FlightFileAccess fileAccess=new FlightFileAccess()直接分配变量
或者,如果您想添加更多的逻辑,就像您有一个构造函数一样,您可以使用静态初始值设定项块,如下所示:
public class Dataflights {
private static final FlightFileAccess fileAccess;
static {
// Static initializer block gets run once when the class is first referenced.
// Not usually used unless you want to add more logic besides just initializing variables.
fileAccess = new FlightFileAccess();
}
private final String path;
public final int id;
public Dataflights(String path) {
this.path = path;
this.id = fileAccess.generateId();
}
static class FlightFileAccess {
private volatile int nextId = 0;
synchronized public int generateId() {
return nextId++;
}
}
public static void main(String[] args) {
Dataflights d = new Dataflights("my/path");
System.out.println("Id is: " + d.id);
}
}
有许多方法可以处理争用。如果您不熟悉Java并发性,我建议您这样做
您在FlightFileAccess类中所处的轨道是正确的。我看不到详细信息,但您可能还希望在remove()
方法的签名中使用synchronized
关键字来首先保护整个函数。然后,一旦你有了工作,就可以使用目标更明确的同步{…}
块来减少单线程的代码量。请编辑你的问题,将代码格式化为代码,并将其缩进。仅仅因为你在书中找到建议,这不会自动成为好的建议。构造函数是否无条件地分配静态字段?这听起来像是非常糟糕的设计。谢谢eric,这是一个错误,所以我修正了它,是的,基本上我想知道我的想法是否正确,因为我们需要使用同一个对象在线程上应用同步,在我提供的示例中,它在构造函数中实例化了静态对象,所以我觉得它是错误的,我认为在构造函数之前实例化要好得多。也感谢这本书的推荐,我已经听过很多次了,所以是的,我必须开始阅读它来理解所有的多重可能性,这不是一个静态构造函数。它是一个实例初始化程序块。它将有与构造函数相同的问题。顺便说一句,这将不会编译,因为该字段是最终字段。如果您的意思是静态初始值设定项块,那么语法是static{…}
。但这是不必要的。您可以直接初始化静态变量,作为其声明的一部分。
Class FlightFileAccess{
private RandomAccessFile database = null;
private boolean remove(String code){
// Other code goes here and there
synchronized (database) {
//Perform deletion code
}
}
public class Dataflights {
private static final FlightFileAccess fileAccess;
static {
// Static initializer block gets run once when the class is first referenced.
// Not usually used unless you want to add more logic besides just initializing variables.
fileAccess = new FlightFileAccess();
}
private final String path;
public final int id;
public Dataflights(String path) {
this.path = path;
this.id = fileAccess.generateId();
}
static class FlightFileAccess {
private volatile int nextId = 0;
synchronized public int generateId() {
return nextId++;
}
}
public static void main(String[] args) {
Dataflights d = new Dataflights("my/path");
System.out.println("Id is: " + d.id);
}
}