Programming 101 By Way of Java

Programming 101


By Way of Java


Instructor: T. Boutell


Transcript for 1/2/96


Stimulants Anonymous

Welcome to the Java programmers' roasteria. A wide variety of stimulating beverages are consumed among the whirring virtual machines.

stevi gefingerpokens jsam.
jsam oufs!
kristen has arrived.
You say, "thanks for coming to the eighth meeting of the java class, folks."
jsam smiles.
You say, "before I start rolling, I'd like to ask if anyone has questions they would like to resolve before I cover new material."
kristen has general confusion about threads and when you need them or not, but that's about it.
You say, "kristen: well, as a rule of thumb, if you want to do something that takes a lot of time, and you don't want to make the browser wait for you, it would be good to do it in your own thread."
kristen says, "okay."
kristen says, "i started changing the sinewave application over to a fractal application with a button that starts a new fractal, and i started to lose focus on how to combine buttons and threads."
kristen says, "i'd like to be able to halt the fractal in progress. right now it starts a new fractal. it works but it is really not very responsive. at the end of class i can pick your brain."
You say, "kristen: interesting. Yes, I can see the confusion there."
You say, "kristen: one way to deal with that would be to just stop the old thread if any, and make a new one, when that button is clicked."
kristen nods. hm. that sounds logical.
You say, "okay. It happens that this week's material does more with threads, including some things relevant to what you are talking about."
You say, "so I'm going to get started."
You say, "Everyone, please open the following URL:"
kristen says, "cool."
You say, "http://boutell.com/~boutell/class/talk.html"
You say, "log into it with your regular handle if you would and say hello, so I'll know you made it."
You say, "you'll see what I mean when you get there."
You say, "great, everyone made it to the server. That's a relief."
stevi cheers Tom!
jsam says, "whee!"
You say, "now, there are a number of new things at work here."
You say, "I'd like to start off by talking about the Internet for a moment. This may be old hat for you guys, but bear with me."
You say, "the Internet is a collection of machines, each of which has a name, or at least a cryptic address."
You say, "machines on the 'net can communicate with each other much like people with telephone lines."
You say, "to talk to someone else, you need their phone number."
You say, "also, they need to have a phone plugged in at that number, and they need to be listening for the ring."
You say, "in Java, and in internet communications in general, we talk a lot about objects of the 'Socket' class."
You say, "Sockets are a great deal like phones, in that you can use one to dial up someone else, or you can sit by one and listen for calls."
You say, "in Java, we distinguish between these two cases. 'Regular' Socket objects are mostly used to call up a server somewhere."
You say, "to call up a server, you need a hostname (or address), and you need a port number."
You say, "the port number is like an extension in your company phone system. You may have quite a few of them."
You say, "on the net, a lot of these 'extension' numbers are standardized. For instance, HTTP (the web protocol) listens on port 80."
You say, "in Java, if we want to listen for incoming calls, we make a 'ServerSocket' object, and we pass the port number to the constructor."
You say, "Java makes this very straightforward, and it's a lot easier than using sockets in most languages."
You say, "any questions so far, or should I forge ahead and look at the source to the client?"
jsam is okay.
stevi votes for forging.
kristen is okay
You say, "OK. Please click on the 'talk.Client' link and take a look at the source code to the Client class."
You say, "notice the first line:"
You say, "package talk;"
You say, "this is how we announce that the classes in this file are part of a 'package.'"
You say, "we are creating our own package, much like java.awt, for instance."
You say, "all of the classes in this package can see each other's regular methods, not just public methods. The rest of the world can't."
You say, "this is nice, because we can do what we want in our own code, without worrying about other programmers doing dumb things from outside."
You say, "you'll find that, when you work with packages of your own, you want to add a directory of your own to your CLASSPATH setting, and keep your packages in subdirectories of that directory."
kristen shivers about classpath settings.
jsam wonders what CLASSPATH means with the various mac environments.
You say, "in my case, I've added /home/boutell/public_html/class as one of the entries in my CLASSPATH, and so java tries looking in the 'talk' subdirectory of that when it sees a reference to that package."
You say, "when web browsers access your applets, they will try subdirectories of the directory your web page is in, so you can just put packages in subdirectories of that. As I have here."
You say, "ie, notice that talk.html is in ~boutell/class, and all the class files are in ~boutell/class/talk."
You say, "now, let's look at the code..."
You say, "the init() method of Client is simple GridBagLayout stuff, which we've seen before, so I'm not going to go into detail there."
You say, "essentially we're laying out the name entry field and the connect button and so forth."
You say, "the next method is the action() method, which we've also seen before. Notice that, if we're not connected already, we call the connect() method there when the connect button is pressed, or the user hits return."
You say, "now, the connect() method is where things get really entertaining."
You say, "this method's purpose is to connect us to the server."
You say, "let's look at the code:"
You say, "outputStrings = new Vector();"
You say, "here we're creating a Vector object. Vectors are handy for all sorts of things. They are a lot like arrays, except that they automatically grow as you add elements to them; they don't have a fixed size."
You say, "this vector is going to be used to keep a queue of strings that need to be sent off to the server."
You say, "ie, things the user has typed in."
You say, "sure enough, the first thing we do after that is get the user's name out of the name field, and add that to the vector."
You say, "next, we need to figure out the address of the server, and the port it is listening on."
You say, "we do that using the getParameter() method, which is part of the Applet class."
You say, "getParameter() lets us access the <param> tags in the HTML page. <param> tags, you'll recall, come between <applet> and </applet>."
You say, "if we have a tag like this:"
You say, "<param name="host" value="boutell.com>"
You say, "then this will fetch it:"
You say, "String host = getParameter("host");"
You say, "if the parameter isn't there, getParameter returns null, so we check for that and set the 'status' label to let the user know."
You say, "we use Integer.parseInt(), which we've seen before, to get the port translated to an integer."
You say, "now, we create the socket (dial the phone):"
You say, "socket = new Socket(host, port);"
You say, "when this succeeds without throwing an exception, we have a live, two-way connection to a server."
You say, "we could read and write bytes of data directly on this socket, but there's a less painful way, thankfully."
You say, "Java has a very nice notion of 'streams', which are convenient ways to read and write information without being too concerned about where it's going. An InputStream might come from a socket, or from the keyboard, or from a piece of memory."
You say, "there are subclasses of InputStream and OutputStream that are specialized for particular tasks. Two of the most useful are DataInputStream and DataOutputStream."
You say, "these classes are great because we can use them to read not just bytes, but integers, floats, strings and the like, with a single method call."
kristen ooohs.
You say, "this is one of the reasons why socket programming is easier in java than in other languages."
You say, "conveniently, the Socket class has a getInputStream() method, which returns a basic input stream. We pass this to the constructor of DataInputStream to get the more useful, turbocharged version we want."
You say, "we do the same for DataOutputStream."
You say, "now, the only catch is, there are three things we need to do at once in this applet:"
You say, "1. Respond to the user's actions in a timely manner."
You say, "2. Read data coming in from the server, and present it to the user."
You say, "3. Write data out to the server."
You say, "we want these things to happen without requiring the user to sit on his hands while they are going on."
You say, "so, as you've probably noticed, we create threads to handle #2 and #3. That leaves the browser free to serve the user, call our action method, and so on."
You say, "notice that, when we create the threads, we keep references to them in the variables inputThread and outputThread. This is useful because, later on, we can compare Thread.currentThread() to them to find out which thread is running."
You say, "it's also useful because we can stop a thread by writing, for instance, 'inputThread.stop();'"
jsam nods.
You say, "when all of this has succeeded, we set the 'connected' flag to true, and we re-label the 'connect' button as a 'disconnect' button, to save a little grief."
You say, "finally, notice that the whole shebang is wrapped up in one big try/catch block. This allows us to avoid worrying about small details of what might go wrong with setting up the socket and the streams, and just do the same thing for all possible disasters: break the bad news to the user and shut down whatever did get started."
You say, "any questions before I move on?"
Tom is going to move into the disconnect method; fire away regardless if you have questions.
You say, "the disconnect method serves to tear down all the hard work done in the connect method..."
You say, "we pass a string in which specifies the reason we want to hang up. It might be because of an error, or because the user hit 'disconnect', or what have you."
You say, "I haven't been saying much about the 'chatFrame' object yet; that's because it's in a separate class file and I'll move to it after this class file. But that's where the actual input and output is shown."
You say, "so we dispose of that, and close the socket, and stop both threads, input and output."
You say, "we check to make sure those variables aren't null first. That's primarily because disconnect() might be getting called from one of those threads. And when we want to do that, we cleverly set the appropriate variable to null so we won't kill ourselves off in disconnect(). Then we exit gracefully when we're ready."
You say, "now, take a look at the run method..."
You say, "recall that we have to have a public void run() method to fulfill our promise to 'implement Runnable' and thus support threads. This is where every thread begins life."
You say, "since we have two threads, all we do here is check Thread.currentThread() to find out which one is running, and call a method just for that thread."
You say, "so, void inputRun() is the 'main function' for the input thread."
You say, "inputRun is very simple. In an endless loop, we use inputStream.readUTF() to read String objects from the server."
You say, "then we call chatFrame.outputLine(s); to hand off those strings to the chat frame for display to the user."
You say, "java's I/O functions are smart about things like going easy on the CPU when they are waiting for input, so a loop like this is very efficient. It mostly sleeps when there is no input."
You say, "I should explain why it's called readUTF() instead of readString()..."
You say, "UTF is the Unicode Text Format, if I have that acronym right. This refers to the fact that Java supports international text, not just one-byte ascii text, right out of the box."
You say, "UTF strings are 'escaped' in a simple way so that plain USA ascii looks like ASCII, and other characters look like escape sequences. Chauvinistic, yet broad-minded."
jsam smiles.
You say, "notice that we have a try / catch block here too. In this case, if something goes wrong with the socket, we set inputRun to null first and then call disconnect. That's so disconnect won't kill off this thread (and interrupt itself). Then we exit, so the thread does go away."
jsam says, "although you want the thread to die, you don't want it to die before the disconnection is complete."
You say, "sam: yes. I don't want it to die before it can kill off the other thread, for one thing."
You say, "now, the outputRun method is similar. It does, however, introduce something New And Different."
You say, "the task of the output thread is simple enough: send any text that's been entered by the user to the server."
You say, "there's an interesting question here, though, and it relates to kristen's question earlier."
kristen perks up.
You say, "how can something the user does, in a text area or button, affect a thread?"
You say, "we could set a variable, of course, and the thread could sleep a lot and peek at the variable occasionally, but that's a crude solution."
You say, "we could kill off a thread and start another one, certainly, but the shotgun approach might not be what we want."
You say, "we definitely wouldn't want to kill the output thread in the middle of writing an earlier string to the user, for instance."
You say, "fortunately, there's a Better Way (tm)."
You say, "it would be nice if we could ask a thread to 'wait until something specific happens.' And we can, using the 'wait()' method."
You say, "to do that, we have to synchronize on the object we're going to be working with first. That means that once we get inside the synchronized code, no one else can touch that object until we let go of it..."
You say, "then, we let go of it temporarily by calling wait() on that object. You can do that on any object; it's a method of the Object class."
You say, "when we call wait() on an object we have synchronized on, our thread stops until another thread takes control of the object and calls notify() on that object."
jsam says, "ow. *all* objects are monitors (ie, can be synchronised)?"
You say, "sam: yes, every object has a monitor, to use the java documentation's terminology."
kristen says, "hm."
You say, "I should mention, for the benefit of anyone put off by this stuff, that I learned this today."
You say, "until today, I used Thread.suspend() and Thread.resume() to get the same effect. But Netscape doesn't allow them, because they are not very safe. A thread should have to signal its willingness to be suspended, the designers felt. And wait() does that."
kristen has a dumb question.
You say, "kristen: by all means. I'm a little nervous about the lack of questions so far, even."
kristen says, "if a method calls another method, do *both* need to be syncrhonized, or just the first one (adnd then anything that happens is synchronized that happens in that method)?"
kristen has this great fear that i am not understanding the basics.
You say, "kristen: the latter case."
kristen says, "okay."
You say, "kristen: claiming or giving up an object's 'monitor' is something that happens at runtime."
jsam says, "synchronization is something that happens to a thread of control, not to a particular object ?"
jsam says, "well, okay, it does happen to an object, but not to a thread object. um."
jsam says, "?"
You say, "sam: how to put this... it is a lock attached to an object. The 'people' trying to get past the lock are threads."
You say, "sam: the lock forces them to go single file."
jsam nods.
kristen says, "does just the method that does the drawing or whatever need to be synchronized, or anything that is hm, running?"
You say, "kristen: if you don't want two threads to tamper with something at once, synchronize on it. That includes paint sometimes, yes."
stevi says, "it seems more like a relay race than synchronization to me."
You say, "stevi: the relay race analogy is pretty good."
stevi says, "i run with the object until i finish, then i hand it off to you."
You say, "stevi: yes."
stevi says, "you can't go until i hand it off to you; i can't go again til you hand it back to me."
Tom nods.
stevi starts to geddit.
You say, "a word about the synchronized keyword: you can synchronize on an object like I do in this method, synchronized (foo) { }, or you can use it as part of the method declaration..."
You say, "if you say 'synchronized void frob()' as a method declaration, that is identical to this:"
void frob() 
{
	synchronized (this)
	{
	}
}
kristen says 'okay' tentatively.
You say, "it's a common case to want to synchronize on 'this', so there's a convenient way to say it."
You say, "now, I know this thread stuff is strange. It's pretty advanced programming, in fact; it's just hard to avoid in java. People make a living understanding this. So Can You (tm)."
You say, "now, let's look at the flushOutputStrings method..."
You say, "while (outputStrings.size() > 0) {"
You say, "'while there's stuff in the vector...'"
You say, "String s= (String) outputStrings.elementAt(0);"
You say, "'haul out the first element, which is a string...'"
You say, "outputStream.writeUTF(s);"
You say, "'and write it out to the socket.'"
You say, "outputStrings.removeElementAt(0);"
You say, "'now remove the element from the vector. Everyone else moves down one, so there's a new element zero if it's not empty yet.'"
You say, "so this loop pulls each string out of the vector and flings it at the server, bazoom."
You say, "now, let's take a peek at the inputLine method, which ends this particular class..."
You say, "synchronized (outputStrings) {"
You say, "'make sure no one else is messing with the vector...'"
You say, "outputStrings.addElement(s);"
You say, "'add the new input from the user...'"
You say, "outputStrings.notify();"
You say, "'and notify anyone who is waiting for the vector that it's ready for inspection.'"
You say, "so, when the user keys in a fresh line of input, we add it to the output queue and call notify() on the queue to wake up the output thread, which is currently in a wait() call, hoping to hear from us."
You say, "finally, we call chatFrame.outputLine(s); to send a copy of the line straight to the user. We do that to save the server the trouble of sending it all the way back to us (we typed it, we know what it says), and so the user gets prompt feedback."
You say, "now, this code is actually a bit incorrect, I've noticed since writing it..."
You say, "it works fine, but if the output thread is currently busy writing earlier output to the server, the user has to wait to get the lock on the queue; notice the synchronized() blocks."
You say, "this is more of a problem in the server code, which we'll look at next week, by which time I will most assuredly have fixed this wee problem."
You say, "the fix, by the way, is to copy the queue to a separate Vector that no one but the output thread ever touches, and then end the synchronized block, before writing to the server, which is what takes time."
You say, "I could leave this unfixed in the client, and no one would ever notice. In the server, though, it's a bigger issue. I can't make other connections wait while another user is written to; one lagged user could bog down everything."
jsam nods. "Alternatively, you could build a thread-safe queue type."
jsam says, "sorry, Queue class."
You say, "now, if that makes your skull hurt, relax; please hit 'back' in your browser and click on 'talk.ChatFrame'..."
You say, "and let me know when you're there."
You say, "this class is a stand-alone frame, as you can see from using the client."
You say, "to get a stand-alone 'unsigned applet window' frame like this, you extend the Frame class."
jsam says, "where is it decided how large the frame (window) should be?"
You say, "sam: in a moment."
You say, "the constructor of this class first calls the constructor for the parent class (the 'superclass'), like so:"
You say, "super("chat");"
You say, "the constructor for Frame just takes a window title."
stevi says, "what does 'unsigned applet window' mean?"
You say, "stevi: 'unsigned applet window' is Netscape-speak. It used to say 'untrusted applet window' which was their way of warning you not to believe that's REALLY a password prompt from your system, or whatever..."
You say, "stevi: because there are obvious security fears about applets popping up misleading frames..."
stevi ahhhs. i'd never have guessed that's what it meant.
You say, "stevi: now they have a scam where you can pay a lot of money and get a cryptographic key in your applet, and then it's considered 'signed' and the broken key goes away. But you can still tell it apart from a regular window, which is good."
jsam says, "interesting."
You say, "so, the constructor's main task is to lay out the frame, using a GridBagLayout just as we tend to do for applet windows."
You say, "'how big will the frame be' is a good question. One good answer is to call 'pack()' after doing all of your layout."
You say, "if you do that, java will look at the layout, determine how big your components 'want' to be, find the smallest rectangle that shrinky-dinks around that, and make the frame that big."
You say, "I do this a lot, because the results are fairly attractive and you get the right amount of space."
You say, "notice that I call show() right after pack(). Unlike most components, frames don't automatically display when they are created. You have to call show() when you're ready."
You say, "I should also point out the outputText variable. This is of class TextArea, which is a new one. TextArea is a lot like TextField, except that it can be multiple rows of text."
You say, "in this applet, we use a TextArea to display the server's output. That requires a bit of hacking, because TextArea doesn't support word wrap out of the box."
You say, "now, take a peek at the handleEvent method."
You say, "handleEvent is a very important method in any component, because all Events come here first."
You say, "usually, we want to stay out of the way, and let the default version of handleEvent() -- the one in our parent class -- do its job, which is often to call action() or mouseDown() or what have you."
You say, "there are exceptions, though. In particular, if the user closes the frame using the system menu in the title bar, we will receive an Event.WINDOW_DESTROY event. And since there is no handy windowDestroy() method, we have to catch that here in handleEvent."
You say, "people don't like frames that won't go away when asked, so it's important to do this."
You say, "you can check the type of any event by looking at the id member, which could be MOUSE_DOWN or WINDOW_DESTROY, et cetera."
You say, "so, in this frame, if we have received a WINDOW_DESTROY event, we call the disconnect() method in the Client object that created us."
You say, "among other things, that method calls dispose() on the ChatFrame object. Calling dispose() is the correct way to get rid of 'real, important things' like windows on your screen that are attached to java objects."
jsam says, "is dispose() a special method, or just a common name?"
You say, "sam: a common name."
You say, "the most important thing in this method, really, is what we do if we *don't* want to deal with the event."
You say, "it is very important that we call the original version of handleEvent instead, and return the result of that."
You say, "otherwise, lots of important things like action() and so forth will never be called."
You say, "in Java, writing 'super.method()' is the right way to insist that we want the parent class version of the method, and not our own 'replacement.'"
You say, "whee! We're out of time, folks."
You say, "I can see that this example is going to keep us busy for a while."
You say, "I'm going to stop and take any questions. Anything goes as far as difficulty is concerned."
You say, "thanks for participating."
kristen has lots of questions but i think i need to sleep on them and absorb.
stevi's with kristen in the need to absorb phase.
jsam says, "thank you for the class, Tom. that was a big learn."
Tom nods. It's been a big learn for him today. A lot of wackiness with threads.
stevi says, "yes, thank you, Tom."
jsam notes that on his mac netscape 3.01, the TextArea has scroll bars in two directions, and the font inside comes through as Chicago, not "Times Roman".
jsam says, "My question regarding disposal is this: if you forget to close a socket but you lose all references to it, will it be automatically closed (eg, by garbage collection) or not?"
You say, "sam: if you lose *all* references to the socket? Yes, but there are no guarantees about when, you see. Garbage collection happens when it's convenient."
You say, "sam: moral: call close() on sockets."
jsam says, "tom: mmm, ok."
kristen says, "tom, so, for mixing buttons and threads, in my case. it should be just one thread that i want to stop and start again with one button. is that a wait/notify thing?"
kristen has 'pause/resume' and too much stuff in her brane.
You say, "kristen: that depends on what exactly the button is supposed to do?"
kristen says, "it's supposed to start a fractal, and another one to pause it halfway if the person gets bored and wants to change colors."
kristen says, "right now it does start the fractal, but my 'clear' button doesn't do anything until the fractal part is done completely (i expected that.)"
stevi smooches all liberally and heads off.
jsam MUST go and eat some lunch. Bye, folks.
You say, "kristen: well, so you don't need to start from scratch?"
You say, "or do you want it to start from scratch?"
kristen says, "I'd like to either cancel the drawing wherever it is and start a new one, or maybe just pause."
kristen says, "if i could figure out one or the other i'd be happy."
kristen has no goals here besides figuring out how to make an applet that has interactivity.
kristen says, "i have an idea that one variable in the actual fractal part could stop it, but i don't know how to force the fractal method to pay attention to anything once it starts."
You say, "kristen: well, if you stash a reference to the thread in a member variable when you create it, then you can call stop() on that thread anytime."
You say, "kristen: which would zap the old one. Then you can just make a new one."
kristen says, "hm. okay."
kristen nods.
kristen says, "zapping is good."
kristen's applets and stuff all have the quality of something one would do on drugs. press the button, get a pretty thing. press it again and get more colors. whee.
You say, "kristen: since your thread is a recursive beastie, not a simple looping beastie, pausing is more troublesome I guess."
You say, "kristen: when do you sleep(), if ever?"
kristen says, "it sleeps in the same place the sinewave did."
kristen says, "it runs exactly like the sinewave applet except the 'draw sinewave' was turned into a recursive fractal thing. and I tacked a button on outside the thread, in the beginning."
You say, "mmm... it's just that I gather your 'draw sinewave' method takes a long time and never sleeps on the way. Unless I've missed something. That should be fine, mind you, but Netscape doesn't have properly preemptive threads."
kristen says, "hm. i don't have the code in front of me. but i remember it calling sleep."
You say, "hmm, actually, I guess it does make sense."
You say, "if it happens once every pass through your recursive function."
kristen says, "i can put it in the background and it will still draw, but it is just very laggy. when i bring the browser forward again it takes too long for it to 'refresh'"
kristen says, "from the offscreen image i guess."
kristen nods. hm.
kristen says, "well you've said a lot that makes sense. i think when i go dink with again i can play with the thread."
You say, "coolness."
Tom closes his log.

Next | Up to the Index

Follow us on Twitter | Contact Us

Copyright 1994-2012 Boutell.Com, Inc. All Rights Reserved.