Summary
I've noticed that, in descriptions of threading, the levels of abstraction are often mixed, which I believe adds to the confusion already present in understanding threading. In this short exerpt from "Thinking in Java fourth edition," I attempt to clarify the situation.
Advertisement
(Exerpt from "Thinking in Java fourth edition")
As the previous section shows, you have choices in how you implement concurrent programs in Java, and these choices can be confusing. Often the problem comes from the terminology thats used when describing concurrent program technology, especially where threads are involved.
You should see by now that theres a distinction between the code thats being executed and the thread that drives it; this distinction is especially clear in the Java libraries because you dont really have any control over the Thread class (and this separation is even clearer with executors, which take care of the creation and management of threads for you). You create tasks and somehow attach a thread to your task so that the thread will drive that task.
In Java, the Thread class by itself does nothing. It drives the task that its given. Yet threading literature invariably uses language like the thread performs this or that action. The impression that you get is that the thread is the task, and when I first encountered Java threads this impression was so strong that I saw a clear is-a relationship, which said to me that I should obviously inherit a task from a Thread. Add to this the poor choice of name for the Runnable interface, which I think would have been much better named Task. If the interface is clearly nothing more than a generic encapsulation of its methods, then the it-does-this-thing-able naming approach is appropriate, but if it intends to express a higher concept, like Task, then that name is more helpful.
The problem is that the levels of abstraction are mixed together. Conceptually, we want to create a task that runs independently of other tasks, so we ought to be able to define a task, and then say go, and not worry about details. But physically, threads can be expensive to create, so you must conserve and manage them. Thus it makes sense from an implementation standpoint to separate tasks from threads. In addition, Java threading is based on the low-level pthreads approach which comes from C, where you are immersed in, and must thoroughly understand, the nuts and bolts of everything thats going on. Some of this low-level nature has trickled through into the Java implementation, so to stay at a higher level of abstraction, you must use discipline when writing code (I will try to demonstrate that discipline in this chapter).
I shall try to clarify these discussions by attempting to use the term task when I am describing the work that is being done, and thread only when I am referring to the specific mechanism thats driving the task. Thus, if you are discussing a system at a conceptual level you could just use the term task without mentioning the driving mechanism at all.
Spot on Bruce! I have to say that although I consider myself experienced enough to understand well the basics of java threading your presentation on the subject did make some things to click in place in my head. I can't tell you how many times when explaining threads to a colleague I struggled to make him understand how the Thread class is merely a handle to the "invisible stream of execution" (or the "process") that "gallops through your code" starting from the Runnable.run(). It impresses me how you managed to clarify this much better by using two specific words: "drive" and "task". Well at least those made the difference in my particular case. Another point I usually make when exaplaining threads is that threading in java is realy a creature of the structured programming world. Threads have to be explained in terms of independent methods rather than in terms of linked objects. And even though monitors are associated with objects that seems to be mostly for convinience. To understand threads one must think of locks again as independent entities. So you have threads, locks, and individual methods (or rather "functions") - no place for objects. I think this collision between structured and object oriented programming is the thing that derails the brains of most threading newbyes. This is what forces the discipline right? You have to be careful how you "weave" the threads into the object structure of the program. Regards, Todor
> It impresses me how you managed to clarify this much > better by using two specific words: "drive" and "task".
What's frustrating is that it took all these years for me to finally see "oh, that's what's actually happening." The problem is the cacaphony of information out there about concurrency, and how much of it (much of my own stuff included) is misleading or wrong.
But on top of that, there's this problem of getting the models mixed. People understand pthreads-style threading, and know how to make it work, and naturally they want to move it into the new realm -- in this case, OO. But from an OO perspective, pthreads are nonintuitive, and they look like a bolted-on solution that doesn't fit. And in fact, they don't fit. In everything else in Java, you have either the compiler or the runtime system looking out for you and reporting problems to you. But suddenly, with threads, your programs are usually broken and you don't know about it, and the only tool you have to discover the problems is "inspection." Basically, you're suddenly thrown backwards into the land of assembly-language-style programming.
What's also frustrating is that I'm only now beginning to understand the problems with threads and concurrency well enough to see what's wrong with threading and start to evaluate some of the other approaches. But I don't have the sense of seeing the issues at 10,000 feet so that I could think about designing some kind of intuitive and safe concurrency mechanism.
Not trying to be cocky, on the contrary, I'm trying to learn. Please give me an example of a signinficant project that actually requires threading that hasn't been handled in one of the Java Libraries included in Java 4 upwards.
I've worked on generously sized projects and I've never found the use for it. I was trying to create a Splash screen a while ago, and I googled and googled everything spoke of threading. I eventually came across swings Timer class by laborously screening through the swing API and BINGO! there was the solution.
There has been many an instance in which I've also intuitively initially thought "threading" because on the emphasis placed on it, eventually I always find a much simpler work around.
Hence I'm just trying to find if it really is important for one to know more than the basics (I'm at the intermediate level so would be great to hear from most of you folks).
Sebastian, The book that I usually recommend is entitled "Java Thread Programming" by Paul Hyde (printed in the ancient 1999 :). It was my first serious introduction to the intricacies of Java threading and I was preatly pleased by it's understandable tone. Also I think the stuff there is largely valid despite the changes in the java memory model done in Java 5. BTW if someone thinks that book has compromised itself (in the way other books about threading discussed on this blog seem to have) please let me know :) Cheers, Todor
Kondwani, One example I can give you is the java.nio library. Writing a web (or any other :) server based on it requires you to handle all threads/locks completely on your own. Furthermore it requires you to understand the "thread safety properties" of every class in that library. Basically writing all kinds of network middleware seems to require you to do the threading on your own - at least from my experience so far. I'm not shure to what extent the new java.util.concurrent package aleviates the problem since I'm not aquianted with it at all - looking foreward to Bruces book for that :)
> > Basically writing all kinds of network middleware seems to > require you to do the threading on your own - at least
Makes sense, I'm mainly re-cycling code, and I'm developing POS client apps so usually don't have to worry about middleware or the architecture at the Server level but I guess it would be nice to dive into...
Man Bruce! Just going through your blogs, you seem to love threads and this concurrent programming thing... I think we should dub you the Thread Master or Java Thread of something thread related - any suggestions?
Maybe real question is : what is the difference between a "process" and a "thread" ? A conclusion that issues from several documents i read (from Tannenbaum's book about System, to the notion of thread in JVM) is : The terminology "thread" depends on the language that implements it and the operating system that executes it.
For example, the fact is that about the JVM, there is no "process" but only "threads" (non-daemon thread, and daemon threads...) Why the writer is unable to speak about a "process" for the "non-daemon thread" ? In the other side, Tannenbaum says about Unix system that a "thread" is owned by a "process" and is executed in the process' context.
Terminology is really problematic. Are we able to define a model for clearly separating "task" notion from "process" and "thread"...
Help would be great to fix this "terminology" problem.
> Man Bruce! Just going through your blogs, you > seem to love threads and this concurrent programming > thing... I think we should dub you the Thread > Master or Java Thread of something thread related > - any suggestions?
For some reason concurrency fascinates me, but at the same time it is very challenging. The learning curve is steep and long, and along the way are lots of place where you can think that you understand it
I think the possibilities of concurrency are tremendous, especially if we can eventually find a model that works well with objects. I also find simulations to be fascinating, and the original OO language (Simula) was designed with simulations in mind, although it's concurrency model was too crude to be easily used.
If you go way back in the archives of Computer Language magazine (which eventually morphed into Software Development magazine), you'll see I did a cover piece where I used setjmp() and longjmp() to create a kind of coroutine system (non-preemptive). That was at least 10 years ago, and I hadn't even scratched the surface at the time.
I seem drawn to things that have such complexity that they are bound to cause me endless frustration. But if I eventually figure it out, I'm able to explain it to people. I think concurrent programming is inevitable, especially with multicore processors on the horizon. And if you look at messaging systems, they must be built on concurrency principles.
> Maybe real question is : what is the difference between a > "process" and a "thread" ?
This is covered in Thinking in Java 3e, but perhaps it wasn't clear enough (I think it will be in the 4e chapter).
A process has its own memory space. It's usually done at the operating system level, with something like a Unix fork(), so the OS must be able to create and manage these things. I would suggest that one reason that Java uses threads and not processes is because the original Mac OS was not multitasking and so couldn't handle processes. That would prevent write once run anywhere (it would be interesting to know what Java would have looked like if OSX had been around at the time).
A thread shares memory with other threads, and runs within a process. So you can have many threads running within one process.
Processes are generally much easier to work with because it's much harder for them to accidentally interfere with each other. Most issues are handled by the OS. The down side to processes is that they tend to be quite heavyweight and so you can't make lots and lots of them (although the BeOS operating system was designed for exactly that). Although threads tend to be lighter weight, that's not guaranteed. In Java, there's a definite startup overhead for threads (which is mitigated somewhat by the new thread pool executor in J2SE5), and the number of threads is usually limited to a few hundred, which can make threading problematic when you want to do simulations that involve thousands or hundreds of thousands of simulation units (some sort of cooperative concurrency is often used in that case, but that's not built into Java).
I would second Todor's suggestion of Paul Hyde's book. It was the first Java threading book I read that combined accuracy with clarity. In comparison:
Wong & Oaks is confusing, incorrect, misleading and even dangerous Doug Lea's book is correct, well structured, but academic in it's coverage and doesn't address some of the Java specific messiness. It's also a very hard book, despite being well edited. The Holub book is odd - it covers in great detail how one might reimplement concurrency utilities in Java, making many good opinionated points about Java, but it assumes a lot of prior knowledge and is negative in tone, which can be distracting. Lewis & Berg is a great reference if you're into performance tuning, infrastructure and straddle the architect / infra fault line but again is very idiosyncratic.
I believe that most thread programming in Java is done by people who do not understand the thread model.
There is clearly room for a new book on Java thread programming
I think the Concurrency chapter in Thinking in Java 4e, which may be the largest chapter in the book, will give a fairly good introduction, and I've had some good help in trying to get things right.
But there's an upcoming book which I think may become a standard for the subject:
Java Concurrency in Practice, by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea (Addison-Wesley 2006). (Some pretty important names, so it's safe to assume this will be an accurate book).
Indicators are that it will be on the shelves by February.