- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要执行一系列 http 请求,每个请求都可能依赖于先前的 http 响应。我已经能够使用各种 AsyncTask“树”来实现这一点,但是随着决策树的增长,AsyncTask 技术变得更加笨拙。
我认为以某种方式使用 SynchronousQueue(或其他类型的队列)是最好的方法,但我似乎找不到任何关于如何将队列用于 http 请求之类的好的指导或教程。
任何人都可以提供有关使用 SynchronousQueue 的任何指导或指向任何好的教程或建议最好的队列类型吗?
最佳答案
使用 java.util.concurrent.SingleThreadExecutor
并制作一个Runnable
在每个 HTTP 操作和结果处理程序之外。您可以在确定是否需要继续进行时向其提交后续任务。
例如,HTTP“任务”将运行并在成功时提交结果“任务”,或在失败时提交错误“任务”。 Result 任务在完成处理后将依次提交另一个 HTTP 任务。使用 SingleThreadExecutor
确保一次只运行一个任务。
你可以使用 ThreadPoolExecutor
如果您可以同时处理飞行中的多个操作。
把所有这些都拿走,然后把它包装在一个 AsyncTask
中管理顶级“启动”并等待一切完成。拥有 ConditionVariable
可能会很有用或者同步“结束”信号的东西(使用完成“任务”),这样你就可以安全地拆除 Executor
.
A SynchronousQueue
在这里对您没有任何帮助,因为它让您进行所有胎面管理。如果您使用 Executor
所有这些都已处理,您只需要处理 Runnable
s 和 Future
秒。这可能就是您找不到任何教程的原因。无论如何,Executor
所有这些都使用下面的队列实现之一!
根据要求,这里是一些框架 Java 代码。不受支持,未经测试。这应该让你开始。如果您不喜欢 ConditionVariable
,您可以使用不同的同步对象.
这是一种通用技术,并非特定于 Android,您可以在其他情况下随意使用它。
这用作状态机,带有 HttpTask
等人形成状态,并通过将下一个状态提交给 ExecutorService
来对转换进行硬编码。 .甚至还有一个“大爆炸在最后,所以每个人都知道什么时候鼓掌”的形式 ConditionVariable
.
有些人可能会考虑 DoneTask
和 FailedTask
矫枉过正,但它使 Next State 机制保持一致,并让 Future<? extends ResultTask>
用作结果的类型安全容器,当然可以防止您错误分配给它。
abstract class BasicTask {
final ExecutorService es;
final ConditionVariable cv;
public BasicTask(ExecutorService es, ConditionVariable cv) {
this.es = es;
this.cv = cv;
}
}
abstract class HttpTask extends BasicTask {
// source omitted.
// you should make a class to prepare e.g. Apache HTTP resources for specific tasks (see below).
}
abstract class ResultTask implements Runnable {
final ConditionVariable cv;
public ResultTask(ConditionVariable cv) {
this.cv = cv;
}
public void run() {
cv.open();
}
}
final class FailedTask extends ResultTask {
final Exception ex;
public FailedTask(ConditionVariable cv, Exception ex) {
super(cv);
this.ex = ex;
}
public Exception getError() { return ex; }
}
final class DoneTask<T> extends ResultTask {
final T results;
public DoneTask(ConditionVariable cv, T results) {
super(cv);
this.results = results;
}
public T getResults() { return results; }
}
class HttpSequence extends AsyncTask<Void,Void,Object> {
// this will capture the ending task
Future<? extends ResultTask> result;
// this is an inner class, in order to set Result. Refactor so these are small.
// if you don't like inner classes, you still need to arrange for capturing the "answer"
final class SomeHttpTask extends HttpTask implements Runnable {
public void run() {
try {
final SomeType thisStep = doTheStuff(lastStep);
if(thisStep.isDone()) {
// we are done here
result = es.submit(new DoneTask<SomeType>(cv, thisStep));
}
else if(thisStep.isFailed()) {
// not done: we can't proceed because of something in the response
throw thisStep.getError();
}
else {
// not done, everything is ok for next step
es.submit(new NextHttpTask(es, cv, thisStep));
}
}
catch(Exception ex) {
result = es.submit(new FailedTask(cv, ex));
}
}
}
final class TheFirstTask extends HttpTask implements Runnable {
// source omitted. just emphasizing you need one of these for each "step".
// if you don't need to set Result, this could be a static inner class.
}
@Override
public Object doInBackground(Void...) {
final ExecutorService es = Executors.newSingleThreadExecutor();
final ConditionVariable cv = new ConditionVariable(false);
try {
es.submit(new TheFirstTask(es, cv));
// you can choose not to timeout at this level and simply block until something happens...
final boolean done = cv.block(timeout);
if(!done) {
// you will need to account for unfinished threads, see finally section!
return new IllegalStateException("timed out waiting on completion!");
}
if(result != null) {
final ResultTask done = result.get();
if(done instanceof DoneTask) {
// pass SomeType to onPostExecute()
return ((DoneTask<SomeTYpe>)done).getResults();
}
else if(done instanceof FailedTask) {
// pass Exception to onPostExecute()
return ((FailedTask)done).getError();
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something unexpected signalled CV!");
}
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something signalled CV without setting result!");
}
}
catch(Exception ex) {
// something outside workflow failed, pass it to onPostExecute()
return ex;
}
finally {
// naive shutdown (doesn't interrupt running tasks): read JavaDoc on ExecutorService for details
es.shutdown();
}
}
@Override
public void onPostExecute(Object result) {
if(result instanceof SomeType) {
// success UI
}
else if(result instanceof Exception) {
// error UI
}
}
}
关于android - 使用 SynchronousQueue 的指南,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8693359/
在从 Socket 连接读取项目的 Java 应用程序中,我需要(出于此处未进一步概述的原因) 输入项由单个线程处理,以便保留其顺序。 在处理之前要缓冲的输入项,以便在其他项仍在处理时可以从套接字读取
我需要执行一系列 http 请求,每个请求都可能依赖于先前的 http 响应。我已经能够使用各种 AsyncTask“树”来实现这一点,但是随着决策树的增长,AsyncTask 技术变得更加笨拙。 我
我有非常模糊的用例,但本质上我需要知道另一个线程是否执行 SynchronousQueue poll (带有超时),并且我想插入项目并取消阻止它。 有什么简单的方法可以做到这一点吗?从我天真的阅读 j
我在调试 SynchronousQueue 时遇到问题。它在 android studio 中,但它的 java 代码应该无关紧要。我将 true 传递给 SynchronousQueue 的构造函数
这两种实现有什么区别?在哪些情况下应优先使用? 最佳答案 如 this post by Alex Miller 中所述 TransferQueue is more generic and useful
new SynchronousQueue() new LinkedBlockingQueue(1) 有什么区别?我什么时候应该对容量为 1 的 LinkedBlockingQueue 使用 Synch
我的应用程序中有一个情况,我需要启动一个异步任务,然后阻止它完成。 (是的,是的,我知道这不是最佳的,但它是我们正在使用的库的产物。) 具体来说,我需要调用一个函数并传递一个回调对象,实际的回调将在单
我想做一个boundedExecutor,只能并行执行固定数量的线程。当添加更多任务时,执行器将阻塞直到其他线程完成。 这是我在其他问题中找到的Executor。 public class Bound
我使用了几乎默认的 newCachedThreadPool,但我想限制线程创建,所以我像这样创建 ExecutorService new ThreadPoolExecutor(0, Runtime.g
我看到了 BlockingQueue 的这些实现,无法理解它们之间的区别。到目前为止我的结论: 我永远不需要 SynchronousQueue LinkedBlockingQueue 确保 FIFO,
我是一名优秀的程序员,十分优秀!