物化和TimerTask:没有API环境下注册该线程(Objectify and TimerTask

2019-08-22 10:07发布

我试图让一个TimerTask设置定期从谷歌App Engine的数据存储中删除条目。 所以我成立了一个ServletContextListener一个Timer

里面contextInitialized ,我已经注册了我的客体类:

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); 但它似乎并没有帮助。

Answer 1:

从的文档java.util.Timer类 :

对应于每个Timer对象是单个后台线程。

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

同时,从App Engine的文档有关使用其Java沙箱线程:

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

因此,这里发生的事情就是Timer对象实例化自己的线程,然后执行物化查询,但由于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();


文章来源: Objectify and TimerTask: No API environment is registered for this thread