当前位置: 首页 > 面试题库 >

Objectify和TimerTask:此线程未注册API环境

薛淳
2023-03-14
问题内容

我正在尝试进行TimerTask设置,以定期从Google App
Engine的dataStore中删除条目。所以我设置了ServletContextListener一个Timer

在中contextInitialized,我注册了我的Objectify类:

ObjectifyService.register(Person.class);

但是,当任务实际运行时,它抱怨没有设置API环境:

Exception in thread "Timer-0" java.lang.NullPointerException: No API environment is registered for this thread.
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:80)
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:90)
    at com.google.appengine.api.datastore.Query.<init>(Query.java:214)
    at com.google.appengine.api.datastore.Query.<init>(Query.java:143)
    at com.googlecode.objectify.impl.cmd.QueryImpl.<init>(QueryImpl.java:72)
    at com.googlecode.objectify.impl.cmd.LoadTypeImpl.createQuery(LoadTypeImpl.java:50)
    at com.googlecode.objectify.impl.cmd.LoadTypeImpl.filter(LoadTypeImpl.java:58)
    at myApp.MyServletContextListener$MyTask.run(MyServletContextListener.java:58)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

有任何想法吗?我尝试将注册该类的行更改为,ObjectifyService.factory().register(Person.class);但似乎没有帮助。


问题答案:

从类的文档中java.util.Timer

与每个Timer对象相对应的是一个后台线程。

而偷看到的内码java.util.Timer类,我们可以看到,它基本上是通过调用实例的线程new Thread()

同时,从App
Engine的文档中
了解有关在其Java沙箱中使用线程的信息:

您必须使用ThreadManager上的方法之一来创建线程。
您不能自己调用​​新的Thread() 或使用默认的线程工厂。

因此,这里发生的是Timer对象实例化了自己的线程,然后该线程执行Objectify查询,但是由于在ThreadManager外部实例化的线程没有为它们设置适当的App
Engine API环境,因此它将引发异常。

您需要重构代码以避免使用Timer和TimerTask类,而应使用基本线程。例如,代替使用:

import java.util.Timer;
import java.util.TimerTask;

...

Timer timer = new Timer();
timer.schedule( new TimerTask()
{
    @Override
    public void run()
    {
        // Objectify query here.
    }
}, 5000 );

您可以改用:

import com.google.appengine.api.ThreadManager;

...

final long tScheduleDelay = 5000;
ThreadManager.createThreadForCurrentRequest( new Runnable()
{
    @Override
    public void run()
    {
        try
        {
            Thread.sleep( tScheduleDelay );
        }
        catch ( InterruptedException ex )
        {
            // log possible exception
        }

        // Objectify query here.
    }
} ).start();


 类似资料:
  • 问题内容: 因此,这可能是一个愚蠢的问题,但是何时使用以下方法注册课程: 当前,我正在类似接口的类的构造函数中执行此操作,该类在其他类中用于简化数据存储对我的应用程序的使用。但是,我收到此错误: 尝试两次注册种类“用户” 所以,我想我的问题是,您多久在一次Objective中注册类? 谢谢! PS这是我的整个课程: 问题答案: 更新资料 这是最佳实践解决方案: 使用您自己的服务,这可以确保在使用O

  • 本文向大家介绍浅谈Timer和TimerTask与线程的关系,包括了浅谈Timer和TimerTask与线程的关系的使用技巧和注意事项,需要的朋友参考一下 1. Timer是一个定时器,它可以根据指定的时间,指定的执行周期来执行固定的任务TimerTask,例子如下: Timer与线程的关系,在Timer源代码中可现如下代码: 1. 以下为Timer的默认构造方法,起调用了自身的一个有参构造函数:

  • DaoCloud 账号的注册 感谢您对 DaoCloud 的关注和支持,本文将带您一步一步地加入到 DaoCloud 的大家庭中。希望您能通过 DaoCloud 快速地学习并灵活地使用 Docker 进行项目代码的开发、测试和部署。 在使用 DaoCloud 提供的优质服务之前,您需要先注册一个属于您或您的团队的 DaoCloud 账号。DaoCloud 十分重视用户体验的简易性和灵活性,所以我们

  • 注册 API 提供注册和配置组件的Fluent方法。这是推荐的注册方式,比过细的XML注册更好。因为它是强类型的且容易被重构,它可以作为XML配置的替代方式或补充。和XML一起使用更为有利。 需求 Castle.Core.dll 和 Castle.Windsor.dll 都需要。为了使用这个API,你需要添加 引用 Castle.MicroKernel.Registration 。后面的示例假设你

  • 我正在使用Pact Go实现来尝试合同测试。我做了一个不起作用的提供者测试,因为我需要模拟我的服务对Twilio的请求。 我已经为我的消费者和这个提供者之间的契约创建了一个Pact对象,然后为我的提供者和twilio之间的契约创建了另一个称为twilioPact的对象。我已经为Twilioendpoint添加了一个POST的交互,但是在pact.log中我没有看到它被注册。我的测试正确地发出了请求

  • Objectify-Appengine 或 Objectify 是一个 ORM 类的库,它简化 Bigtable 以及 GAE 中的数据持久性。作为一个映射层,Objectify 通过一个简洁的 API 将自身插入到 POJOs 与 Google 的重型设备之间。您可以使用一个熟悉的 JPA 注释子集(尽管 Objectify 不实现完整的规范)以及少量生命周期注释,来存留和检索 Java 对象形