Objectify和TimerTask:没有为此线程注册API环境 [英] Objectify and TimerTask: No API environment is registered for this thread

查看:163
本文介绍了Objectify和TimerTask:没有为此线程注册API环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着让一个 TimerTask 设置为定期从Google App Engine的数据存储中删除条目。因此,我使用 Timer 设置了 ServletContextListener



contextInitialized 中,我注册了Objectify类:

  ObjectifyService .register(Person.class); 

然而,当任务实际运行时,它会抱怨没有设置API环境: p>

 线程Timer-0中的异常java.lang.NullPointerException:此线程没有注册API环境。 
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)
在java.util.TimerThread.mainLoop(Timer.java:555)
在java.util.TimerThread.run(Timer.java:505)

有什么想法?我尝试将注册类的行改为 ObjectifyService.factory()。register(Person.class); 但它似乎没有帮助。

解决方案

java.util.Timer class 的文档:


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

java.util的内部代码,以了解如何使用Java编写的代码。 Timer class ,我们可以看到它基本上通过调用 new Thread()来实例化线程。



同时,从 App Engine的文档了解有关使用线程的内容他们的Java沙箱:


Yo您必须使用 ThreadManager 上的某种方法来创建您的线程。 您无法自己调用新的Thread()或使用默认的线程工厂。 Timer 对象实例化了它们自己的线程,然后执行Objectify查询,但由于在ThreadManager外部实例化的线程没有为它们设置适当的App Engine API环境,所以它会抛出一个例外。

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

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

...

定时器定时器=新的定时器();
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)
{
//记录可能的异常
}

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


I'm trying to get a TimerTask set up to remove entries from Google App Engine's dataStore periodically. So I set up a ServletContextListener with a Timer.

Inside the contextInitialized, I have registered my Objectify classes:

ObjectifyService.register(Person.class);

However, when the task actually runs, it complains that no API environment has been set up:

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)

Any ideas? I've tried changing the line that registers the class to ObjectifyService.factory().register(Person.class); but it didn't seem to help.

解决方案

From the documentation of java.util.Timer class:

Corresponding to each Timer object is a single background thread.

And peeking to the inner code of the java.util.Timer class, we can see that it basically instantiates the thread by invoking new Thread().

Meanwhile, from App Engine's documentation about the use of threads in their Java sandbox:

You must use one of the methods on ThreadManager to create your threads. You cannot invoke new Thread() yourself or use the default thread factory.

So what happened here is the Timer object instantiated their own thread, which then executes the Objectify queries, but since threads instantiated outside ThreadManager does not have the proper App Engine API environment set up for them, it throws an exception.

You need to refactor your code to avoid using the Timer and TimerTask classes and use basic threads instead. For example, instead of using:

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

...

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

You could instead use:

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和TimerTask:没有为此线程注册API环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆