Java Runtime Environment

With App Engine, you can build Java web applications that use Google's scalable infrastructure and services.


App Engine runs your Java web application using a Java 7 JVM in a safe "sandboxed" environment. App Engine invokes your app's servlet classes to handle requests and prepare responses in this environment.

Cloud Tools for Eclipse adds new project wizards and debug configurations to your Eclipse IDE for App Engine projects. You can deploy your App Engine projects live to production from inside Eclipse.

Cloud Tools for IntelliJ enables you to run and debug App Engine applications inside IntelliJ IDEA. You can deploy your App Engine projects live to production without leaving the IDE.

Third-party plugins are available for other Java IDEs as well. For example, for NetBeans see NetBeans plugin for Gaelyk Framework.

App Engine uses the Java Servlet 2.5 standard for web applications. You provide your app's servlet classes, JavaServer Pages (JSPs), static files and data files, along with the deployment descriptor (the web.xml file) and other configuration files, in a standard WAR directory structure. App Engine serves requests by invoking servlets according to the deployment descriptor.

The secured "sandbox" environment isolates your application for service and security. It ensures that apps can only perform actions that do not interfere with the performance and scalability of other apps. For instance, an app cannot spawn threads in some ways, write data to the local file system or make arbitrary network connections. An app also cannot use JNI or other native code. The JVM can execute any Java bytecode that operates within the sandbox restrictions.

The App Engine platform provides many services that your code can call. Your application can also configure scheduled tasks that run at specified intervals.

If you haven't already, see the Java Getting Started Guide for an interactive introduction to developing web applications with Java technologies and Google App Engine.

Selecting the Java runtime

The App Engine API for Java is represented by the appengine-api-*.jar included with the SDK (where * represents the version of the API and the SDK). You select the version of the API your application uses by including this JAR in the application's WEB-INF/lib/ directory. If a new version of the Java runtime environment is released that introduces changes that are not compatible with existing apps, that environment will have a new version number. Your application will continue to use the previous version until you replace the JAR with the new version (from a newer SDK) and re-upload the app.

The sandbox

To allow App Engine to distribute requests for applications across multiple web servers, and to prevent one application from interfering with another, the application runs in a restricted "sandbox" environment. In this environment, the application can execute code, store and query data in the App Engine datastore, use the App Engine mail, URL fetch and users services, and examine the user's web request and prepare the response.

An App Engine application cannot:

  • write to the filesystem. Applications must use the App Engine datastore for storing persistent data. Reading from the filesystem is allowed, and all application files uploaded with the application are available.

  • respond slowly. A web request to an application must be handled within a few seconds. Processes that take a very long time to respond are terminated to avoid overloading the web server.

  • make other kinds of system calls.

The filesystem

A Java application cannot use any classes used to write to the filesystem, such as An application can read its own files from the filesystem using classes such as An application can also access its own files as "resources", such as with Class.getResource() or ServletContext.getResource().

Only files that are considered "resource files" are accessible to the application via the filesystem. By default, all files in the WAR are "resource files." You can exclude files from this set using the appengine-web.xml file.


Features of the java.lang.System class that do not apply to App Engine are disabled.

The following System methods do nothing in App Engine: exit(), gc(), runFinalization(), runFinalizersOnExit()

The following System methods return null: inheritedChannel(), console()

An app cannot provide or directly invoke any native JNI code. The following System methods raise a java.lang.SecurityException: load(), loadLibrary(), setSecurityManager()


An application is allowed full, unrestricted, reflective access to its own classes.

It can query any private members, call the method java.lang.reflect.AccessibleObject.setAccessible(), and read/set private members.

An application can also reflect on JRE and API classes, such as java.lang.String and javax.servlet.http.HttpServletRequest. However, it can only access public members of these classes, not protected or private.

An application cannot reflect against any other classes not belonging to itself, and it can not use the setAccessible() method to circumvent these restrictions.

Custom class loading

Custom class loading is fully supported under App Engine. An application is allowed to define its own subclass of ClassLoader that implements application- specific class loading logic. Please be aware, though, that App Engine overrides all ClassLoaders to assign the same permissions to all classes loaded by your application. If you perform custom class loading, be cautious when loading untrusted third-party code.

Class loader JAR ordering

Sometimes, it might be necessary to redefine the order in which JAR files are scanned for classes in order to resolve collisions between class names. In these cases, loading priority can be granted to specific JAR files by adding a <class-loader-config> element containing <priority-specifier> elements in the appengine-web.xml file. For example:

	<priority-specifier filename="mailapi.jar"/>

This places "mailapi.jar" as the first JAR file to be searched for classes, barring those in the directory war/WEB-INF/classes/.

If multiple JAR files are prioritized, their original loading order (with respect to each other) will be used. In other words, the order of the <priority-specifier> elements themselves does not matter.

The JRE white list

Access to the classes in the Java standard library (the Java Runtime Environment, or JRE) is limited to the classes in the App Engine JRE White List.

No signed JAR files

App Engine's precompilation isn't compatible with signed JAR files. If your application is precompiled (the default), it can't load signed JAR files. If the application tries to load a signed JAR, at runtime App Engine will generate an exception like

java.lang.SecurityException: SHA1 digest error for com/example/SomeClass.class
    at java.util.jar.JarVerifier.processEntry(
    at java.util.jar.JarVerifier.update(
    at java.util.jar.JarVerifier$
    at sun.misc.Resource.getBytes(
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(
    at java.lang.reflect.Method.invoke(
    at java.lang.ClassLoader.loadClass(

There are two ways to work around this:


A Java application can create a new thread, but there are some restrictions on how to do it. These threads can't "outlive" the request that creates them.

An application can

or use the factory object returned by with an ExecutorService (e.g., call Executors.newCachedThreadPool(factory)).

However, 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.

An application can perform operations against the current thread, such as thread.interrupt().

Each request is limited to 50 concurrent request threads. The Java runtime will throw a java.lang.IllegalStateException if you try to create more than 50 threads in a single request.

When using threads, use high level concurrency objects, such as Executor and Runnable. Those take care of many of the subtle but important details of concurrency like Interrupts and scheduling and bookkeeping.

Background threads

Code running on manual or basic scaling instances can start a background thread that can outlive the request that spawns it. This allows instances to perform arbitrary periodic or scheduled tasks or to continue working in the background after a request has returned to the user.

Java concurrency can lead to issues that are hard to debug. To avoid using threads, consider Task Queues, Scheduled Tasks or Pub/Sub.

A background thread's logging entries are independent of those of the spawning thread. You can read more about background threads in App Engine's ThreadManager documentation.

import java.util.concurrent.atomic.AtomicLong;

AtomicLong counter = new AtomicLong();

Thread thread = ThreadManager.createBackgroundThread(new Runnable() {
  public void run() {
    try {
      while (true) {
    } catch (InterruptedException ex) {
      throw new RuntimeException("Interrupted in loop:", ex);

If code running in an automatic scaling module attempts to start a background thread, it raises an exception.

The maximum number of concurrent background threads is 10 per instance.

The Java SDK and tools

The App Engine Java SDK includes tools for testing your application, uploading your application files, and downloading log data. The SDK also includes a component for Apache Ant to simplify tasks common to App Engine projects.

You can also use the plugin for Apache Maven to support your development. This plugin is included in the app-engine-java component of the Cloud SDK.

The development server runs your application on your local computer for development and testing. The server simulates the App Engine datastore, services and sandbox restrictions. The development server can also generate configuration for datastore indexes based on the queries the app performs during testing.

A multipurpose tool called AppCfg handles all command-line interaction with your application running on App Engine. AppCfg can upload your application to App Engine, or just update the datastore index configuration so you can build new indexes before updating the code. It can also download the app's log data, so you can analyze your app's performance using your own tools.

Concurrency and latency

Your application's latency has the biggest impact on the number of instances needed to serve your traffic. If you process requests quickly, a single instance can handle a lot of requests.

Single-threaded instances can currently handle one concurrent request. Therefore, there is a direct relationship between the latency and number of requests that can be handled on the instance per second. For example, 10ms latency equals 100 request/second/instance.

Multi-threaded instances can handle many concurrent requests. Therefore, there is a direct relationship between the CPU consumed and the number of requests/second.

Java apps support concurrent requests, so a single instance can handle new requests while waiting for other requests to complete. Concurrency significantly reduces the number of instances your app requires, but you need to design your app specifically with multithreading in mind.

For example, if a B4 instance (approx 2.4GHz) consumes 10 Mcycles/request, you can process 240 requests/second/instance. If it consumes 100 Mcycles/request, you can process 24 requests/second/instance. These numbers are the ideal case but are fairly realistic in terms of what you can accomplish on an instance.