03-11-2015, 05:58 AM
It is possible to run things asynchronly (in a other thread) and go back to synchronous (/ callbacks)?
I need this because I want to do database requests and one requests took 0.2 - 1.2ms.
My implementation in java:
And a example use of the queue:
I need this because I want to do database requests and one requests took 0.2 - 1.2ms.
My implementation in java:
package tv.rewinside.database.bukkit.util;
import com.google.common.collect.Queues;
import java.util.Queue;
import java.util.logging.Level;
import tv.rewinside.database.bukkit.DatabasePlugin;
public class DatabaseQueue extends Thread {
	private final Queue<Runnable> runnables = Queues.newConcurrentLinkedQueue();
	public DatabaseQueue() {
		super("Database Queue");
		this.setDaemon(true);
	}
	public synchronized void addRunnable(Runnable runnable) {
		this.runnables.add(runnable);
		this.notify();
	}
	private synchronized void blockCurrentThread() {
		try {
			while (this.runnables.isEmpty()) {
				this.wait();
			}
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}
	public int getCount() {
		return this.runnables.size();
	}
	 
	public void run() {
		while (!this.isInterrupted()) {
			this.blockCurrentThread();
			while (!this.runnables.isEmpty()) {
				try {
					this.runnables.poll().run();
				} catch (Exception ex) {
					DatabasePlugin.getInstance().getLogger().log(Level.WARNING, "Exception while execute database task", ex);
				}
			}
		}
	}
}
public interface DatabaseCallback<T> {
	public void run(T result);
}
And a example use of the queue:
public void getPlayer(final String uuid, final DatabaseCallback<DatabasePlayer> callback) {
		DatabasePlayer dbPlayer = this.cachedPlayers.get(uuid);
		if (dbPlayer != null) {
			callback.run(dbPlayer);
			return;
		}
		// Load player -> Async
		this.plugin.getQueue().addRunnable(new Runnable() {
			 
			public void run() {
				DatabaseCache.this.syncCallbackCall(callback, DatabaseCache.this.loadPlayer(uuid));
			}
		});
	}
private DatabasePlayer loadPlayer(String uuid) {
		DatabasePlayer dbPlayer = this.plugin.getConnection().getPlayer(uuid);
		if (dbPlayer == null) return null;
		this.cachedPlayers.put(uuid, dbPlayer);
		this.cachedPlayersFromName.put(dbPlayer.getLastName(), dbPlayer);
		return dbPlayer;
	}
private <T> void syncCallbackCall(final DatabaseCallback<T> callback, final T arg) {
		if (Bukkit.isPrimaryThread()) {
			callback.run(arg);
			return;
		}
		Bukkit.getScheduler().runTask(this.plugin, new Runnable() {
			 
			public void run() {
				callback.run(arg);
			}
		});
	}
 If we could create a new thread for a certain function, then it should be really easy to make WorldEdit use it 