java - 高效等待资源

标签 java multithreading asynchronous

我想知道解决这个问题最有效的方法是什么。

我有一个多线程数据库实现(例如 LevelDB),我希望它能够处理同步,因为它可以做得更好。但是,我想异步初始化数据库,而不阻塞任何线程,除非他们想在打开数据库之前使用数据库。

大致如下:

public class Storage {
  Database db;

  public Storage() {
    open();
  }

  private void open() {
    new Thread(new Runnable() {
      public void run() {
        // attempt to open db here, i.e. change the value of Storage.db from null
        // into Object
      }
    }).run();
  }

  public void accessMethod() {
    // this method should only use a non-null Storage.db value, it should block
    // until the thread above does not set the value of db to be an Object
  }

  public void nonAccessMethod() {
    // this method is not concerned with the value inside Storage.db and should not 
    // block while the thread above is running
    // example: memory cached operations on the db which will be executed after
    // the thread above finishes and "unlocks" Storage.db
  }
}

我想出了这个解决方案,但效率不是很高:

public class Storage {
  ReentrantLock lock;

  Database db;

  public Storage() {
    lock = new ReentrantLock();

    open();
  }

  private void open() {
    lock.lock(); // to be released in thread below

    new Thread(new Runnable() {
      public void run() {
        // heavy work here while populating Storage.db

        lock.unlock();
      }
    }).run();
  }

  // returns true if the database is not yet open and that we need to release
  // the lock once our code segment completes
  private boolean blockIfNotOpen() {
    if (lock.tryLock()) {
      lock.unlock();       // <<   this code segment sucks

      return false;
    } else {
      lock.lock();

      return true;
    }
  }

  public void accessMethod() {
    boolean wasNotOpen = blockIfNotOpen();

    // "blocking" code here

    if (wasNotOpen) {
      lock.unlock();
    }
  }

  public void nonAccessMethod() {
    // not concerned with Storage.db and therefore not trying to lock
  }
}

我不喜欢这个解决方案,因为在填充 Storage.db 后很长时间,它仍然在存储的实现中同步对数据库的访问,而实际上 DB 内部有一个底层系统,可以更好地处理并发(例如:DB公开工作线程等)。

在 Storage 对象上同步不是一个解决方案,因为它会始终同步,而不是仅在 Storage.db 为 null 时同步。

注意:如果您担心锁,我保证在 Storage 的构造函数完成之前不会有并发调用。 :) 因此,所有并发都发生在构造函数之后。

最佳答案

我认为解决方案是在构造函数中使用 ReadWriteLock - writeLock().lock()writeLock().unlock()在数据库初始化并从数据库使用者使用 readLock() 后。

另一个选项,使用 Future:

public class Storage {
    private final Future<Database> dbFuture = Executors.newSingleThreadExecutor().submit(
        new Callable<Database>()
        {
            public Database call()
            {
               return new Database(...);//Long running DB initialisation
            }
        }
    );

    public void accessMethod()
    {
       Database db = dbFuture.get();// will wait while the call() is not completed yet.
    }
}

关于java - 高效等待资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25082815/

相关文章:

c# - 多重锁定任务(线程)

python - Python 中的多线程 MD5 校验和

javascript - 异步范围

java - maven 3.0+ 在 'mvn deploy' 上跳过插件执行

不拉伸(stretch)宽度的Java Swing JPanel

python - Django 的 call_command 在线程内的问题

javascript - 获取新数组后组件未更新

java if 语句在 if(item instanceof nomclass) 中不起作用

java - 如何在 map Java8中保留FCFS和重复键

c# - 等号登录数据 "causes"开始GetRequeststream失败