سؤال

لديّ العديد من مؤشرات الترابط التي تقوم بتسلسل كائنات "البيانات" الخاصة بي إلى الملفات. يعتمد اسم الملف على حقلين من الكائن

  class Data {
    org.joda.DateTime time;
    String title;

    public String getFilename() {
      return time.toString() + '_' + title + ".xml";
    }

من الممكن أن يكون لكائنان البيانات نفس "الوقت" و "العنوان" ، وبالتالي اسم الملف نفسه.

هذا أمر مقبول ، وأنا سعيد إما أن يتم حفظها. (ربما هم نفس كائن البيانات على أي حال إذا كانت هذه هي نفسها)

مشكلتي هي أن خيوط اثنين (أو أكثر) تكتب إلى ملف في نفس الوقت ، مما تسبب في XML المشوه.

لقد ألقيت نظرة على java.nio.channels.filelock ، لكن الأمر يتعلق بالقفل على مستوى VM ، ولا يناسب بشكل خاص القفل داخل الخيوط.

يمكنني المزامنة على dataio.class (ولكن هذا سيؤدي إلى حدوث حمولة كبيرة ، لأنني أرغب حقًا في مزامنة الملف الفردي).

سيكون المزامنة على كائن الملف عديمة الفائدة ، حيث يمكن أن تمثل كائنات الملفات المتعددة نفس ملف النظام.

يتبع الكود:

class DataIO {
  public void writeArticleToFile(Article article, String filename, boolean overwrite) throws IOException {
    File file = new File(filename);
    writeArticleToFile(article, file, overwrite);
  }

  public void writeDataToFile(Data data, File file, boolean overwrite) throws IOException {
    if (file.exists()) {
      if (overwrite) {
        if (!file.delete()) {
          throw new IOException("Failed to delete the file, for overwriting: " + file);
        }
      } else {
        throw new IOException("File " + file + " already exists, and overwrite flag is set to false.");
      }
    }

    File parentFile = file.getParentFile();
    if (parentFile != null) {
      file.getParentFile().mkdirs();
    }

    file.createNewFile();

    if (!file.canWrite()) {
      throw new IOException("You do not have permission to write to the file: " + file);
    }

    FileOutputStream fos = new FileOutputStream(file, false);
    try {
      writeDataToStream(data, fos);
      logger.debug("Successfully wrote Article to file: " + file.getAbsolutePath());
    } finally {
      fos.close();
    }
  }
}
هل كانت مفيدة؟

المحلول

هل يمكن أن تتدرب () السلسلة التي هي اسم الملف. ثم تزامن على السلسلة الداخلية.

class DataIO {
  public void writeArticleToFile(Article article, String filename, boolean overwrite) throws IOException {
    synchronized(filename.intern()) {
       File file = new File(filename);
       writeArticleToFile(article, file, overwrite);
    }
  }

نصائح أخرى

إذا كنت أقرأ هذا بشكل صحيح ، فلديك كائن بيانات يمثل ملفًا واحدًا.

يمكنك التفكير في إنشاء مجموعة مخططة بناءً على كائن البيانات. ربما يكون لديك concurrenthashmap

ConcurrentMap<Data,Lock> lockMap = new ConcurrentHashMap<Data,Lock>();

لا عندما تريد الكتابة إلى هذا الكائن يمكنك القيام به:

Lock lock = lockMap.get(someMyDataObject);
lock.lock();
try{
   //write object here
}finally{
   lock.unlock();
}

ضع في اعتبارك أنه سيتعين عليك كتابة طريقة Hashcode و Equals بناءً على العنوان ووقت البيانات

أوافق على أن استخدام التزامن هو التقنية التي يجب استخدامها. ما تحتاجه هو كائن متميز لكل تقليب الملف ، والأهم من ذلك نفس الكائن في كل مرة. قد يكون أحد الخيارات هو إنشاء فصل يسمى FileLock:

public class FileLock {
    DateTime time;
    String title;

    public FileLock(DateTime time, String title) {
        this.time = time;
        this.title = title;
    }

    override equals/hashCode based on those two properties

    static Hashtable<FileLock, FileLock> unqiueLocks = new Hashtable<FileLock, FileLock>();
    static lockObject = new Object();

    public static FileLock getLock(DateTime time, String title) {
        synchronized (lockObject) {
            FileLock lock = new FileLock(time, title);
            if (unqiueLocks.ContainsKey(lock)) {
                return unqiueLocks.get(lock);
            }
            else {
                unqiueLocks.put(lock, lock);
                return lock;
            }
        }
    }
}

ثم سيستخدمها المتصلين مثل:

synchronized (FileLock.getLock(time, title)) {
    ...
}

ضع في اعتبارك أن هذا لديه تسرب ذاكرة لأن علامة التصنيف تستمر في النمو مع التباديل الجديد للملف/الوقت. إذا كنت بحاجة إلى ذلك ، فيمكنك تعديل هذه التقنية بحيث يستدعي المتصلين من GetLock أيضًا طريقة RELEASELOCK التي تستخدمها للحفاظ على نظافة علامة التجزئة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top