使用@Scheduled和@Async,Java进行线程安全

时间:2016-01-15 20:02:41

标签: java spring concurrency

我拿了这段代码:

private Queue<Object> myQueue = new ConcurrentLinkedQueue();

public enqueue(Object obj) {
  myQueue.add(obj);
}

@Scheduled(fixedRate=1000)
public void publish() {
  final List objsToPublish = Lists.newArrayList();
  final int listSize = myQueue.size();
  for (int i = 0; i < listSize; i++) {
     objsToPublish.add(myQueue.poll());
  }

  expensiveWriteOperation(objsToPublish);
}

然而,如果在此软件中运行的某些其他操作期间,publish()会取消控制,那么这是一个问题,所以我试图让昂贵的调用异步,如下所示:

private Queue<Object> myQueue = new ConcurrentLinkedQueue();

public enqueue(Object obj) {
  myQueue.add(obj);
}

@Scheduled(fixedRate=1000)
public void publish() {
  final List objsToPublish = Lists.newArrayList();
  final int listSize = myQueue.size();
  for (int i = 0; i < listSize; i++) {
     objsToPublish.add(myQueue.poll());
  }

  work(objsToPublish);
}

@ASync
void work(List objsToPublish) {
  expensiveWriteOperation(objsToPublish);
}

我关心两件事。

1)这个代码是否有效,即使在任何时候调用enqueue,甚至是mid-work()?

2)我是否以正确的方式从队列中传递数据?

1 个答案:

答案 0 :(得分:1)

在您的情况下,work()方法必须是公共的,并且必须从具有publish()方法的类外部调用。如果这是Spring,那么您最有可能使用动态代理,在这种情况下,从其他地方调用publish()后,@Async方法的work()注释将不再起作用,因为您已经在内部代理实例。

试试这个:

interface AsyncInternalWrapper {
    void work(List objsToPublish);
}


@Service
public class AsyncInternalWrapperImpl implements AsyncInternalWrapper {
    @Async
    public void work(List objsToPublish) {
      expensiveWriteOperation(objsToPublish);
    }
}

然后

@Autowired
private AsyncInternalWrapper wrapper;

@Scheduled(fixedRate=1000)
public void publish() {
  ....

  wrapper.work(objsToPublish);
}

另一方面,由于这是一个预定的流程,因此不需要用户交互。那么让publish()调用返回更快的真正好处是什么?您可能想要考虑这种异步操作提供的优势(如果有的话),而不是在没有好的参数的情况下过度设计。

关于你的问题,请记住,publish()将由Executor服务在自己的线程中执行,所以你自然就已经在做了#34; async&#34;呼叫。我猜这是使用并发队列的动力。 @Async会发生的事情是,除了执行publish()

之外,您正在产生(或从线程池中获取)另一个线程