2016-06-04 3 views
-1

파일의 각 행에 대해 고유 한 ID를 생성하는 Java 프로그램을 작성했습니다. 고유 한 ID를 얻기 위해 동일한 프로그램을 실행하는 여러 작업이있을 수 있습니다. 이 ID는 모든 파일의 각 행마다 고유해야합니다. 나는 값을 파일에 직렬화하여이 작업을 시도했다. 여러 작업이이 프로그램을 사용하게 될 것이므로이 방법을 동기화했습니다. 단일 작업에서는 코드가 제대로 작동하지만 동시에 여러 작업을 실행하려고하면 동기화 된 메서드가 실패합니다. 이미 실행중인 메서드가있을 때 동일한 개체에 대해 메서드가 다시 호출되는 것처럼 보입니다. 동기화 된 메서드가 객체를 잠그지 않는 이유는 무엇입니까? 내가이 아래에 오류가 동시에이 메서드를 호출 할 때Java 동기화 된 메서드가 객체를 잠그지 않습니다.

CreateId2 id = CreateId2.getInstance(); 
long j = id.idGenerate(); 

-

public class CreateId2 implements Serializable { 

private static final long serialVersionUID = 1L; 
private long i; 

public synchronized long idGenerate() { 

    long k = this.generateId(this); 
    return k; 

} 
private long generateId(CreateId2 id){ 

    long returnedVal = id.getI(); 
    try { 
    returnedVal = id.readObject(); 
    //System.out.println("previous modiefiied returnedVal is" + returnedVal); 
    } catch (FileNotFoundException ex) { 
     id.setI(200L); //start from 200 for the first time 
     returnedVal=id.getI(); 
    } catch (Exception ex2) { 
     ex2.printStackTrace(); 
    } 
    returnedVal = returnedVal +1; 
    id.setI(returnedVal); 
    //System.out.println("returnedVal is " + returnedVal); 
    try { 
    id.saveObject(id); 
    } catch (Exception ex3) { 
     ex3.printStackTrace(); 

     } 
    return returnedVal; 
} 

public void saveObject(CreateId2 id) throws IOException{ 
    //System.out.println("saving object " + id.getI()); 
    File savedFileName = new File("C:\\Users\\sam\\Desktop\\tests\\test.ser"); 
    FileOutputStream savedOutput = new FileOutputStream(savedFileName); 
    ObjectOutputStream oos = new ObjectOutputStream(savedOutput); 

    oos.writeObject(id); 
    oos.flush(); 
    // close the writing. 
    oos.close(); 
    //System.out.println("saved. value is " + id.getI()); 
} 

public long readObject() throws IOException, ClassNotFoundException{ 
    //System.out.println("read object is called. value is " + ci2.getI()); 

    File savedFileName = new File("C:\\Users\\sam\\Desktop\\tests\\test.ser"); 
    FileInputStream savedInput = new FileInputStream(savedFileName); 
    ObjectInputStream ois = new ObjectInputStream(savedInput); 

    //long val = Long.parseLong(ois.readObject().toString()); 

    CreateId2 ci2 = (CreateId2) ois.readObject(); 
    //System.out.println("value of valtemp " + ci2.getI()); 
    long val = Long.valueOf(ci2.getI()); 

    ois.close(); 
    return val; 
    // close the writing. 

} 

public long getI() { 
    return i; 
} 

public void setI(long i) { 
    this.i = i; 
    //CreateId2.i = i; 
} 

// setter methods 

private static CreateId2 instance = null; 
private CreateId2() { } 
public static CreateId2 getInstance() { 
    if (instance == null) { 
     instance = new CreateId2(); 
    } 
    return instance; 
} 

} 

내가 같이이 메서드를 호출 해요 -

아래는 ID가 내가 쓴 코드를 생성합니다. 또한 생성 된 ID는 더 이상 고유하지 않습니다.

java.io.EOFException 
    at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2325) 
    at java.io.ObjectInputStream$BlockDataInputStream.readUnsignedShort(ObjectInputStream.java:2806) 
    at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2864) 
    at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1072) 
    at java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:704) 
    at java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:830) 
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1601) 
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517) 
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771) 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) 
    at helperPackage.CreateId2.readObject(CreateId2.java:66) 
    at helperPackage.CreateId2.generateId(CreateId2.java:23) 
    at textFile.RandomTest.main(RandomTest.java:18) 
+0

동기화가'EOFExceptions'을 발생시키지 않습니다. 지나간 스트림을 읽으면'EOFExceptions'이 발생합니다. 이것은 데이터베이스에 대한 작업입니다. – EJP

+0

맞습니다. 하지만 병렬로 작업을 실행하려고 할 때만 EOF 예외가 발생합니다. 어떤 이유로이 예외가 왜 던져지고 있는지 파악할 수 없습니다. –

답변

0

synchronized은 동일한 JVM의 동일한 객체에서 동기화하는 두 클래스에서만 작동합니다. 모니터 오브젝트의 인스턴스가 여러 개 있거나 여러 JVM에서 실행 중이거나 일} 처리 시스템에서 각 작업이 자체 클래스 로더를 가져 오는 경우 synchronized이 작동하지 않습니다. 임의의 128 비트 값이고 고유 한 "보장 된"유형 4 UUID를 사용하십시오.

+0

답변 해 주셔서 감사합니다. 동일한 JVM을 사용하고 있습니다. 기존 인스턴스를 가져 와서 동일한 객체에 대한 메소드를 호출하려고했지만 올바르게 수행하지 않을 수 있습니다. 나는 이클립스 인스턴스의 두 창을 열어서 그것을 테스트하고 차례로 두 개의 루프를 돌렸다. 여기에 무슨 문제가있을 수 있습니까? –

+0

@SamH 만약 "open 2 eclipses ... blah blah"라면 2 개의 별도 프로세스를 사용하고 있으므로 별도의 2 개의 JVM을 사용하고 있으므로 동기화 된 키워드를 사용하여 동기화 할 수 없습니다. 왜 그런지 묻는다면 대답은 간단합니다 : 어떤 변수를 동기화 (LOCK이라고 부를 수 있습니다)하고 있기 때문에 다른 개체 - 런타임 컨텍스트가 LOCK1! = LOCK2와 같은 프로세스 사이에서 공유되지 않습니다. – Antoniossss

0

짐 개리슨 월이 문제로 인해 많은 상황에 응답 한 (충돌하면 우주의 나이 초당 100 만 UUID를 생성하는 경우에도 일어날 가능성이 의미에서 보장)

.

idGenerate()는 스레드 안전하지만 싱글 생성자는 스레드로부터 안전하지 않습니다 :이 문제를 일으킬 수있는 또 하나의 가능한 (공통) 실수를 추가 할. 많은 수의 CreateId2 개체를 만들 수 있습니다. an example of a thread-safe Singleton

+0

링크 (Auto ThreadSafe Singleton Pattern)에서 두 번째 옵션을 시도했지만 여전히 동일한 오류가 발생했습니다.이걸 쓴 다음이 클래스를 테스트 클래스로 확장합니다. public class ThreadSafeSingleton { \t private static final CreateId2 인스턴스 = new CreateId2(); \t \t 보호 ThreadSafeSingleton() { \t}을 만들면 기본적으로 \t //이 \t 공공 정적 개체의 getInstance() { \t \t 반환 인스턴스를 스레드 \t // 런타임 초기화; \t} } –

관련 문제