An interview with James Gosling

Bill Venners probes the formidable mind of Java's creator

JavaOne Today: What have you been working on recently here at Sun Labs?

Gosling: These days, I'm putting together a group to work on developer tools based on work done by the NetBeans folks, who put together this really nice framework for building tools.

One of the things I'm trying to do is to build a set of tools that professional developers would use. Typically, tool vendors tend to go after the mass-market developer, and I guess I'm not one of them, so they generally don't interest me. And, by and large, all the tool developers have kind of ignored the higher-end developers. So I'm spending some time thinking about that.

But, in actual fact, I've spent most of the last year working on the realtime spec for Java. That's really what's occupied me for most of the last year. I was doing that pretty much full-time until three or four weeks ago, when we finally got a camera-ready copy of the book off to Addison-Wesley.

JavaOne Today: Which book?

Gosling: The realtime specification for Java. It's a spec that was done under the Java Community Process. JavaOne Today: Could you give an overview of what's in that spec and what it's all about?

Gosling: The realtime spec for Java is all about how you write programs in Java on realtime systems. And there are a number of components to it -- simple things like dealing with accurate dates, scheduling events. Most of the hard things have to do with deterministic timing.

James Gosling

In the realtime world, what people care about is performance, to a certain extent. But more important than performance is, generally, determinism.

When you say, "I want this to be executed at that time," in general, by God, you mean it. And then it's not allowed to slip. And that has effects in two areas. One is scheduling, and there's all kinds of exotic scheduling algorithms that can be in there, and the realtime spec has a general framework for putting in all kinds of schedulers.

The other side of it is that there's one big source of non-determinism in timing in Java right now, and that's garbage collection. And garbage collection is really the number one hard problem.

On the one hand, people look at garbage collection and what it gives you, and they by and large really like it. Particularly folks in the realtime world like garbage collection a lot because it's tremendously useful for increasing the reliability of systems and speeding up development time. It just helps to hold the whole robustness story tremendously.

JavaOne Today: You said particularly the realtime people like that.

Gosling: Yeah. Well, because they tend to be even more worried about systems that crash. With a lot of these realtime systems, if the software crashes, an actual person dies. It's a control system for an airplane or a robot arm -- you're just getting ready to stop the arm and you garbage collect and the arm just keeps going because nobody's telling it to stop. And it takes out a wall or innocent passers-by or something. And so you can't tolerate that kind of thing.

And so there was a general consensus that we wanted to have garbage collection in there but we didn't want to live with the hiccups that you get when your average garbage collector kicks in. All garbage collectors have the effect that they tend to shut down the system for some interval of time. And some of them you can actually tune the interval.

So, like in HotSpot, there's a limited amount of control that's possible over how long each GC step takes. But if you're writing an application whose timeliness needs to be tighter than what something like the HotSpot VM can do, then you're in trouble.

One of the things that we decided fairly early on was that an easy out on this problem would be to, say, only use "realtime garbage collectors." That's garbage collectors that have essentially zero pause time because they either back out or are doing things truly in parallel.

A couple of people in the group did a literature survey and they concluded that real realtime garbage collectors essentially didn't exist. There were a lot of things which were claiming to be realtime garbage collectors that were close but not good enough. And the usual extent of closeness was that the people were saying, "Well, we're realtime because we never pause more than a millisecond." Or, "We're realtime because only one chance in a billion will we ever actually back off and do a full mark-and-sweep."

Unfortunately, both of those invalidate the GC algorithm in some applications. In the realtime world, people are worried about the worst case. They don't care at all about the average case or the best case, they care about the worst case. And if the worst case is that this algorithm will actually do a full mark-and-sweep -- shut the thing down for seconds -- then it doesn't work, even if it happens once in 10 or 15 days of running. If the thing that's running is the thing that's controlling the flutter of the wingtip of an F-16, after 10 days the airplane turns into dust. And that doesn't work.

For GC algorithms that have fairly small minimum times, often people will claim that they have a realtime algorithm, and then they'll say it's got a maximum pause time of a millisecond. And that works for some applications and doesn't for others. One way to characterize realtime algorithms is based on the maximum latency that they can tolerate. And some of them can live just fine with a millisecond; some need something much finer than that.

So what we ended up doing was defining a way to allow a special kind of thread to run even while the garbage collector is running. And if you know much about garbage collectors then you think about what is it that has to be true about a thread if it's going to run while the garbage collector is running. You end up with a fairly onerous set of restrictions. Namely that whatever the thread does, it does not allow it to touch an object in the garbage collector heap, and it's not allowed to move a pointer to one of these objects around.

And so we've defined two subclasses of thread, one called the realtime thread, which is a thread that has all kinds of extra scheduling parameters besides just the priority. And then there's another subclass of that called the no-heap realtime thread, which is one that also has the ability to run while the garbage collector is running. But those threads are not allowed to access heap memory. And the way that they are able to work is that there's a way to allocate what are called "immortal objects." An immortal object is one that is allocated -- it stays there forever and it never, ever goes away.

The immortal objects correspond pretty much to what people actually do as standard practice in realtime coding today. Generally when people are doing serious realtime work they pre-allocate everything. And then they sort of go into their realtime reading windows with the things which realtime never, ever allocates. Because it turns out that almost all the allocators in the world actually have non-deterministic timing.

See, almost everybody's malloc() or free routine has non-deterministic timing. And so in general, people don't use them for the intense realtime application. So the whole no-heap thing/immortal objects, if you describe that to an average Java programmer, they'd say, "Oh my God, this is really awful." But if you describe it to somebody who's been doing realtime programming, their reaction is sort of, "Gee, that's what I do today. It's not a big problem."

But it gives them the advantage of this universe where people doing these really time-critical things can actually interact with the other world that is done in Java, and get all the advantages of writing programs in Java, and also get all the portability stuff. That's really the most important piece.

JavaOne Today: How do the new scheduling capabilities work?

Gosling: With scheduling, there are some new objects introduced and one is called the scheduler. And a scheduler determines when threads should get started up. And one of the parameters of the scheduler is if it's a no-heap thread, it can then start while the garbage collector is running.

But normally, the scheduler is similar to what happened in the typical thread scheduler. It's looking at the queues of threads that are available to be one. They picked one, and in most everyday computer systems these fairly simple priority-based schemes work pretty well.

In realtime systems, generally you've got a notion of a deadline when this particular computation has to be done. And so there are ways to associate properties with threads like what its deadline is, what the expected amount of work is. And that gives a scheduler more information to sort of trade off which things to run now.

It's an open-ended framework, so that people can invent new schedulers and plug them in. There's also hooks in there for doing what people in the realtime world call feasibility analysis. Namely, you've got a set of threads, and you ask the question, "So does this make any sense?" If you've got three or four threads, each of which wants 100 percent of the CPU all the time, it makes no sense at all because you'd need three or four CPUs. Or three or four times as much CPU as you've got.

So you can do things like back out or not start systems, or go into some sort of fail-safe mode. JavaOne Today: What do you mean by "back out"?

Gosling: Like not start the system. It's application dependent. When the feasibility analysis fails, what do you do?

JavaOne Today: So the VM does the feasibility analysis before it starts? Or does the application do it?

Gosling: The application effectively is in charge of invoking it. Because what the application does is it sets up a set of threads. And then it asks the scheduler "Is this feasible?" And if it is, then the system carries on. If it's not, then the application decides what to do. And it may do things like decide to cut back on its workload somehow. Or it may just even refuse to start.

It's sort of like having the "on" button on your airplane, if it turns it on and says, "Sorry, install a new CPU."

JavaOne Today: Is this going to be incorporated into all future VMs? Or will there be realtime VMs and a not-necessarily-realtime VMs?

Gosling: Yeah, it really ends up being two. There's the Java VM and then there's sort of a specialized class of Java VMs which would be the realtime Java VMs.

JavaOne Today: So there are certain kinds of applications then that would run on realtime VMs that just wouldn't work on regular VMs?

Gosling: Correct. The standard VM is not optimizing for the realtime performance. In general, what non-realtime systems are optimizing for is not timeliness but throughput. So you're trying to see how much raw performance you can get out of the whole system. And whether you're hitting your deadlines on a millisecond by millisecond basis isn't really relevant.

JavaOne Today: Why don't we switch gears and talk a bit about mobile code. I've had a few concerns about the practicality of sending objects across the network, and I would be curious to hear what your thoughts are. Let's start with finalization.

One of the issues that has come up in Jini discussions is cleaning up after mobile objects. If I'm a client and I receive a mobile Jini service object, that object can consume my local resources by firing off a thread, opening a socket, and so on.

From a Jini lookup service, I can grab service objects about whose interface I have absolutely no prior knowledge. I can grab them by name. I can use the browser methods to find things that look interesting and grab them. If I have prior knowledge of the interface of the object, then there's probably a cleanup method that I'm supposed to call when I'm done with it. If the object is nice, it will relinquish all of my resources that it consumed when I invoke the cleanup method.

Gosling: Right.

JavaOne Today: But first of all, it may not be nice. And second of all, I may not have any prior knowledge of that interface. So how do we make sure that clients don't always run out of resources when they're using mobile code?

Gosling: There are several answers to that. One is when you stop referencing that object, it goes away. And things that it refers to go away. And the finalizer will get called.

In other words, that it's actually pretty rare to bring in some mobile object, not have some idea what interface it implements. Generally, these pieces of mobile code are used in things like editor plug-ins or database plug-ins, and they tend to do a Class.forName() or some sort of look-up that gives you this new Class object. And you do a newInstance() on it. And then you say, well gee, are you a plug-in for this area? Are you a device manager? Or are you a printer device manager? Then you can start talking to it.

If you have absolutely no idea what you're expecting, just take an arbitrary object in, there's not a whole lot you can do with it other than say, "Hey, isn't this nice?" And almost always, people do have standardized interfaces for these things.

And if you're designing one of these standardized interfaces and having the imported stuff go through some active and passive phases where you're getting rid of, dumping resources and that, then defining a method to clean things up is a good thing to do.

JavaOne Today: There's also denial-of-service attacks or bugs where even if you do call the cleanup method, if the method forgets to kill a thread, that thread doesn't go away.

1 2 3 Page 1
Page 1 of 3
How to choose a low-code development platform