Thursday, May 29, 2008

Threads

1. Why cannot we synchronized public object to lock the memory for avoiding multi-thread access?

A:synchronized has nothing to do with locking memory, but controlling access to a block of code, which may access and change the memory/database/file contents, the integrity of which might be compromized by multi-thread simultaneous access or changes. Here, I intentionally missed how synchronized works, uses what kind of working mechanism. Read other part of the FAQ for that, please. public/private/protected access modifiers have no relationship with synchronized, even they share a word "access". They are for encapsulation, in other words, information sharing or hiding. Like your family, you may want certain information to be public, some to be known only by your relatives or close friends, some to be kept only to your family members. Some might be kept to yourself only, hoho, a secret. They are different concepts and serve different purposes.

2. I found this statement about thread in some tutorial on Internet, Is it true?

The main thread must be the last thread to finish execution. When the main thread stops, the program terminates.

A: Absolutely wrong!

The correct one:
JVM creates one user thread for running a program. This thread is called main thread. The main method of the class is called from the main thread. It dies when the main method ends. If other user threads have been spawned from the main thread, program keeps running even if main thread dies. Basically a program runs until all the user threads (non-daemon threads) are dead.This is actually most GUI (Swing) application works. The main thread creates a thread for the GUI frame work; then it finishes and becomes dead. The GUI will still running until the user closes it or something else kills it. Microsoft GUI application basically works the same way.

A simple sample code (even not GUI) here!

class T extends Thread {
boolean runflag = true;
public T(String name){
super(name);
}
public void run() {
int i = 0;
while (runflag) {
System.out.println(getName() + ": " + i++);
try
{
sleep((int)(700*Math.random()));
}
catch (InterruptedException e) {
}
}
System.out.println(getName() + " is stopping.");
}

void setRunFlagFalse() {
runflag = false;
}

public static void main(String args[]) {
T t1=new T("t1");
T t2=new T("t2");
T t3=new T("t3");

t1.setDaemon(true);
t1.start();

t2.start();
t3.start();
try
{
// let three threads run
Thread.sleep(600);
}
catch (InterruptedException e) {
}

// t2 will stop
t2.setRunFlagFalse();

System.out.println("t3 will not stop after main stop");
System.out.println("t1 will stop after all user threads stopped");
System.out.println("Use ^C to stop everything, when you had enough");
System.out.println("main thread is stopping.");
}
}

3. What is the basic concept of synchronized keyword, is it responsible to our data integrity?

A: The key concept of synchronized keyword is locking the code to prevent other thread to access the critical code when one thread is processing it. You need acquire the monitor/lock from an object to lock it, and one object only has one lock/monitor. That is why when one thread acquired the lock/monitor, other threads have to wait. Why you need to lock the code? Mostly you need to keep the integrity of your data, and which is very application specific. The locking mechanism actually knows nothing about it. It is NOT responsible for your data integrity at all. It is you, the application programmer, who is responsible for it. For example, if you want to keep the integrity of your client's bank account balance, you must synchronize all methods, which have access to and can change the balance. If you leave a loophole there, you probably will be fired by your boss, not Dr. Gosling or someone else who designed the locking mechanism. I just want to scare you... However, when you are synchronizing the code, which has access to the client's account balance, you probably still can change his/her email address or list of hobbies for advertisement purposes. Of course, if you are really serious on that stuff too, you might want to synchronize the code, which has access those data independently.Programmers need to practice some examples to really understand it. Some times, I still get confused. Concurrent programming is not an easy subject. It is not Java specific either. Race condition, dead lock, critical section, semaphore, monitor, thread scheduling, thread pooling, etc. etc...I'm still in the learning process... How about we learn together.

4. Why we should call Thread.start() to start a Thread? I called the run() method, no error or exception at all, why?

A: When you call Thread start() method, JVM will create a new Thread, then call run() method of the new Thread. The new Thread will run concurrently with the original calling Thread.If you directly call the run() method, the Thread will act as a normal Java object. No new Thread will be created. The code will run sequentially. Try the following code to see the difference, and get a feeling of concurrency.

// MyRun.java
public class MyRun implements Runnable {
public static void main(String argv[]) {
MyRun r = new MyRun();
Thread t = new Thread(r);

// t is still running after Main finished
t.start();

// No new thread created, Main finishes after run() returns
// t.run();

try {
// See concurrency if you call t.start()
// See sequential if you call t.run()
for (int i = 0; i < i =" 0;">

5.Thread t = null; t.yield(), is this legal? If it is, what is the effect of the statement?

A: Yes, but it is bad coding style. It is equivalent to Thread.yield(), which will cause the current thread to yield, and becomes ready state. The purpose of yield() is let other Thread has a chance to execute.Since yield() is a static method of Thread class, the only concern to compile is the type, that is why t.yield(); and Thread.yield(); are exact the same. However, it is confusing human beings. It is bad, but legal practice. It is good for you to really understand what is static method.

6. In some mocking exam, after the definition of Thread t = new Thread(); then both yield(); and t.yield(); are marked as alternative answers for causing the current running thread to pause. Is it generally correct?

A: No! It is generally incorrect. In some special situation, it will compile and work, however, it should still be considered as bad coding practice. The special case is: when yield(); is called inside a Thread class ( in a main, or other method ).You should use Thread.yield() instead to accomplish the task. For more discussion, read the question above.The following example shows you the general case, if you call yield(); it will not compile.

// ThreadTest.java
import java.io.*;
class MyThread extends Thread {
public void run(){
for (int i=0; i<5; i =" " t =" new">

7. What are the differences between notify() and notifyAll()? Do they release the object lock?

A: notify() does NOT relinquish the lock - it just lets the JVM know that it will be possible to wake up a Thread that called wait() when the current Thread exits the synchronized code. If you have more than one Thread wait() on an object, notify only wakes up one of them - you can't predict which one. notifyAll() tells the JVM that all Threads waiting will be eligible to run. The JVM will pick one - probably by looking at the priorities.

8. When Thread.sleep() is called inside a synchronized method or block, does the Thread release the object lock?

A: No, Thread definitely does not release the lock before it goes to sleep, if it is in a synchronized method or block. That is why we should use wait(), notify(), notifyAll() defined in Object in synchronized method or block. Do not sleep() there unless you want the program totally stop, please! Write some code, you will see it easyly. Or read JDK Doc here: http://java.sun.com/j2se/1.3/docs/api/java/lang/Thread.html#sleep(long)Here is a example, sleepInsteadOfWaitNotify() method causes t2 and t3 totally starved to death.

public class SleepTest implements Runnable{

public void run() {
while (true){
sleepInsteadOfWaitNotify();
}
}

synchronized void sleepInsteadOfWaitNotify() {
while (true) {
System.out.println(Thread.currentThread().getName() + "Go to sleep");
try{
Thread.sleep(400);
}
catch (Exception e){
System.out.println(e);
}
System.out.println(Thread.currentThread().getName() + "wake up");
}

}

public static void main (String[] args){
SleepTest t = new SleepTest();

Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);

t1.setName("t1");
t2.setName("t2");
t3.setName("t3");

t1.setDaemon(true);
t2.setDaemon(true);
t3.setDaemon(true);

t1.start();
t2.start();
t3.start();

try {
// let daemon threads run
Thread.sleep(10000);
}
catch (InterruptedException e) {
}
System.out.println("If user thread is dead, all daemon threads die. ");
}
}

9. In what situation, an IllegalThreadStateException will be thrown?

A:1) If the thread was already started, you call start() again.
2) If this thread is active, you call setDaemon().
3) A deprecated method countStackFrames() also throws IllegalThreadStateException.

10. What will be affected by assign a name to a thread using setName("YourThreadName")?

A:

Quote from JDK documentation:
Every thread has a name for identification purposes. More than one thread may have the same name. If a name is not specified when a thread is created, a new name is generated for it.

Nothing changes by assigning your Thread a name. It only gives you the convenience of debug, since it has a name you know.

11. What is Thread.interrupt()supposed to do?

A:

interrupt is supposed to end the sleep or wait state of a Thread prematurely by causing an InterruptedException.

12.What is Daemon Threads?

A: A daemon thread opposites to a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads. You threads are default to user thread unless you explicitly use method setDaemon(boolean on) to set it as daemon thread. Note: You cannot call setDaemon() after Thread has started, otherwise, an IllegalThreadStateException (RuntimeException) will be thrown. Make sure you read the JDK documentation of Thread and ThreadGroup. Javadoc is your best teacher to tell you almost anything and everything about Java Threads.See sample code at ThreadTest.java

13. Why Thread methods stop(), resume(), suspend() deprecated? How can we stop a thread without call stop()?

A: Why? Read here Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?
How? See the following example:

public class T extends Thread {
boolean runflag = true;
public T(String name){
super(name);
}
public void run() {
int i = 0;
while (runflag) {
System.out.println(getName() + ": " + i++);
try
{
sleep((int)(400*Math.random()));
}
catch (InterruptedException e) {
}
}
System.out.println(getName() + " is stopping.");
}

public void setRunFlagFalse() {
runflag = false;
}

public static void main(String args[]) {
T t1=new T("t1");
T t2=new T("t2");
T t3=new T("t3");
t1.start();
t2.start();
t3.start();
try
{
// let three threads run
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
// stop them
t1.setRunFlagFalse();
t2.setRunFlagFalse();
t3.setRunFlagFalse();
}
}

15. Can I use Thread.interrupt() to kill a thread? Is it a good idea?

A: Yes, you can. As long as your handle the InterruptedException tricky enough in your Thread.run() method, you can use interrupt() to kill a thread.However, it is absolutely a bad idea to do this. Thread.interrupt() is a general purposed method to interrupt or stop whatever a thread is doing now, such as sleep, wait, or living. If you used a general purpose method to mean killing a thread, you create a side effect, and invite unaware programmers to make mistake since they only read Sun's Thread javadoc.Stop is general; stop life is special. General includes special, but general does not imply special. If it does, it is a side effect. If stop sign on the street does also imply stop life, that would be really bad!!!Never do this kind of stunt, please!

Please follow KISS rule in your code, Keep It Simple and Stupid, or Keep It Simple and Straight forward. Do your boss and current/future coworkers a favor please!

There is one exception, if you're the boss, you can do and ask your employees do whatever you want. If they do not follow your order, fire them!

If you want read more discussion about and opposite side of my opinion, read here!

16. What does the Thread.join() method do? Can you give an example?

A: The current running thread currT call another thread jobthread.join(), then wait until the jobthread to die.

For example, the current running thread, which spawns the jobthread to do something (do a long calculation, load several images, call somebody through satilite, etc. etc.). The jobthread has been coded to do its job and then terminate or die, in other words, the jobthread.run() method ends. The current thread will rely on jobthread's completion to continue its own work. The effect of calling jobthread.join() statement is that currT waits for jobthread to complete

public class JoinDemo {
public static void main(String[] args) {
Job job = new Job();
Thread jobthread = new Thread(job);

jobthread.start();
try {
// the current thread will wait until the job done
jobthread.join();
}
catch(Exception e){
}
System.out.println("Job done");
// do something else
}
}
class Job implements Runnable {
public void run(){
int i;
for (i=1; i<=200; i++ ){ if (i % 10 != 0) { System.out.print(i + ", "); } else { System.out.println(i); } } } }

17. Is class wide lock and instance lock independent of each other?

A: Yes. Why?

Every Java Object has one lock, and only one lock. If you want enter synchronized code, you have to acquire the lock first. When you enter the static synchronized code, you need to acquire the lock on the Class object.

When you enter the synchronized instance code, you need to acquire the lock on the instance object.

However, they are different objects with different locks, and independent of each other.When you call a synchronized static method you get a lock on NONE OF the instances of the class, except the Class object itself. Please pay attention to the difference between class and Class. Run the following code, it will tell you the whole story.

class MyObj {
String sName;

public MyObj(String name) {
sName = name;
}

// The Class Object of MyObj will be locked
// However, staticMethod() and instanceMethod() are independent of each other
public static synchronized void staticMethod(String sThreadName) {
try {
System.out.println(sThreadName + ": staticMethod start lock");
Thread.sleep((long)(Math.random() * 2000 + 1));
System.out.println(sThreadName + ": staticMethod finish lock");
}
catch (InterruptedException e) {
}
}

// The instance Object MyObj of will be locked
// However, staticMethod() and instanceMethod() are independent of each other
public synchronized void instanceMethod(String sThreadName){
try {
System.out.println(sThreadName + ": " + sName + ": instanceMethod start lock");
wait((long)(Math.random() * 2000 + 1));
System.out.println(sThreadName + ": " + sName + ": instanceMethod finish lock");
notifyAll();
}
catch (InterruptedException e) {
}
}
}

public class Test extends Thread{
String sTrdName;

// 2 objs for testing lock
static MyObj o1 = new MyObj("myobj1");
static MyObj o2 = new MyObj("myobj2");

public Test(String name){
super();
sTrdName = name;
}

public void run() {
while (true){
// Lock the Class object of MyObj
MyObj.staticMethod(sTrdName);

// Lock the instances object of MyObj
o1.instanceMethod(sTrdName);
o2.instanceMethod(sTrdName);
}
}

public static void main (String[] args){
Test t1 = new Test("t1");
Test t2 = new Test("t2");

t1.setDaemon(true);
t2.setDaemon(true);

t1.start();
t2.start();

try {
//let Daemon thread run
Thread.sleep(7000);
}
catch (InterruptedException e) {
}
System.out.println("If user thread is dead, all daemon threads die. ");
}
}

// Output of the program clearly tell you the story
/*
t1: staticMethod start lock
t1: staticMethod finish lock
t2: staticMethod start lock
t1: myobj1: instanceMethod start lock
t1: myobj1: instanceMethod finish lock
t1: myobj2: instanceMethod start lock
t2: staticMethod finish lock
t2: myobj1: instanceMethod start lock
t2: myobj1: instanceMethod finish lock
t2: myobj2: instanceMethod start lock
t1: myobj2: instanceMethod finish lock
t2: myobj2: instanceMethod finish lock
t2: staticMethod start lock
t2: staticMethod finish lock
t2: myobj1: instanceMethod start lock
t1: staticMethod start lock
t1: staticMethod finish lock
t1: myobj1: instanceMethod start lock
t2: myobj1: instanceMethod finish lock
t2: myobj2: instanceMethod start lock
t1: myobj1: instanceMethod finish lock
t1: myobj2: instanceMethod start lock
t2: myobj2: instanceMethod finish lock
t2: staticMethod start lock
t1: myobj2: instanceMethod finish lock
If user thread is dead, all daemon threads die.
*/

18. How to call wait(), notify(), notifyAll() in synchronized static methods?

A: Direct calling those methods will not compile since those are instance methods inherited from Object. When you call wait(), you are actually calling this.wait(), this does not exist in static methods.

How can we solve the problem? There are two ways to do it.

  1. Call wait(), notify(), notifyAll() methods of your Class object, by using MyClass.class.wait(). synchronized static methods locks the Class, you release lock of the same object.

  2. Instantiate a static Object dummy in your class, you can use synchronized block, which locks dummy, in your static method. Then you can call dummy.wait(), dummy.notify(), ... in those blocks.
    This is better when you have more than one set of static methods, which needs locked independently, you can use more than one dummy objects for that purposes.

    If your problem is something like that a Queue problem where add and remove are static methods working on static array. Lock the array object!!! See sample code snippet below.

static Object[] ary = new Object[50];
static void method1() {
System.out.println("do something not need to lock the ary...");
synchronized(ary){
System.out.println("do something on ary Object..");
try{
ary.wait();
}
catch(InterruptedException e) {
}
System.out.println("do something else on ary Object..");
}
System.out.println("do something else not need to lock the ary...");
}

19. What is race condition?

A:

Quote from The Java Tutorial:
Race conditions arise from multiple, asynchronously executing threads try to access a single object at the same time and getting the wrong result.

An excellent explanation of race condition here! Not Java specific!!!
http://www.kulua.org/Archives/kulua-l/199901/msg00025.html

20. What is Thread Deadlock? How to avoid it?

A: A deadlock occurs when one object is waiting for another to release a lock, and that object is also waiting. A circular dependency occurs, and then the waiting thread will wait forever, or deadlocked.The key to prevent deadlock: Do not hold a lock while waiting another resource that also requires locking.Read from Sun's tutorial:
http://java.sun.com/docs/books/tutorial/essential/threads/deadlock.html
Play with the famous Dining Philosopher Problem (not invented by Java!) Applet and learn the important concepts when you have fun.

21. What is Thread Starvation? How to avoid it?

A: For any reason, one or more threads never get a chance to run, or be blocked for a long time if not forever.Many reasons can cause Thread starvation:

  1. Threads are deadlocked.

  2. Thread is blocked by I/O, the I/O never become available again.

  3. Other threads with higher priority run selfishly, never give other thread a chance to run.

  4. Synchronized methods/blocks forget to release the lock/monitor. In Java, wrongfully using sleep/yield instead of wait/notify/notifyAll has a very good chance to cause deadlock/starvation.

  5. Your Thread scheduling system does not working correctly.

  6. ...

How to avoid/correct them? Find out what causes your thread starvation, and correct them.

22. When a Thread die? Can a dead Thread be restarted?

A: No. a dead Thread cannot be restarted.

  • If you call its start() method after its death, IllegalThreadStateException will be thrown.

  • Even the Thread is dead, but you still can call its other method. Why? Simple, the Thread is just another Java Object. For example, if you call its run() method again, it will be just a sequential procedure call, no concurrent execution at all.

  • The exit() method of class Runtime has been called and the security manager has permitted the exit operation to take place.

  • Non daemon threads die, either by returning from call of the run() method or by throwing an exception that propagates beyond the run() method.

  • Daemon Threads die when all user Threads died.

23. When will a Thread I/O blocked?

A: When a thread executes a read() call on an InputStream, if no byte is available. The calling Thread blocks, in other words, stops executing until a byte is available or the Thread is interrupted.

Serialization

1.What class can be serialized? What cannot?

A: Almost all JDK classes are serializable except

  • Classes with only static and/or transient fields. For example, Math, Arrays, etc.

  • Classes representing specifics of a virtual machine. For example, Thread, Process, Runtime, almost all classes in the java.io and many classes in java.net packages are not serializable

I/O Streams, Reader/Writer

2. Creating a File object does not mean creation of any file or directory, and then when does the creation of physical file take place?

A: The answer is it depends...

The physical file might be created 10 years ago by one of your long gone colleagues , or will be created on the next step of running when your program tries to write something onto the not-yet-exist file by using FileOutputStream or FileWriter.

You can also call createNewFile() of the java.io.File object to create a new, empty file named by its abstract pathname if and only if a file with this name does not yet exist.

The file might never be created since the program does not have write permission (of java.io.FilePermission) in that specified directory.

The file might never be created simply because the program never try to do anything on it, absentminded programmer, of course.

The java.io.File object might just represent a directory, which might not be a file at all.

Read The Java Tutorial It is free. Read javadoc, and compare the exception thrown by File and FileWriter constructors will help as well.

3. Is it possible to change directory by using File object?

A: No, You cannot change the directory by using a file object.

Instances of the File class are immutable; that is, once created, the abstract pathname represented by a File object will never change.

However, you can use one File object to find the directory you want, and then create another File object for the directory you want to go to.

4. How to create a new directory by using File object?

A: Using class File method mkdir() or mkdirs(). See code here:

// MakeDir.java
import java.io.*;

public class MakeDir {
public static void main(String args[]){
// make sure sub-directory "mmm" does not exist
File dir=new File("mmm");
System.out.println(dir.mkdir());// true


// make sure at least two of "hhh\\lll\\nnn" does not exist
File multidir=new File("hhh\\lll\\nnn");
System.out.println(multidir.mkdir()); // false
System.out.println(multidir.mkdirs()); // true

// make sure at least two of "..\\ccc\\ddd\\eee" does not exist
File updir=new File("..\\ccc\\ddd\\eee");
System.out.println(updir.mkdir()); // false
System.out.println(updir.mkdirs()); // true

// If you run the code second time,
// the result will be different. Why?
}
}

5. What are the differences between FileInputStream/FileOutputStream and RandomAccessFile? Do you have a good example on it?

A: Remember never mixing RandomAccessFile with Streams!!! RandomAccessFile class is more or less a legacy from c language, the Stream concepts/C++ were not invented then.

This example deals with File, FileInputStream, DataOutputStream, RandomAccessFile. Play with it; try to understand every bit of the output. IOTest.java

6. What are the difference between File.getAbsolutePath() and File.getCanonicalPath()? Can they return different result?

A: Find your answer by reading this:

http://java.sun.com/j2se/1.3/docs/api/java/io/File.html

Yes, they can return different results! See the following example. Pay attention to the comments.

import java.io.*;

public class T
{
static void testPath(){
File f1 = new File("/home/jc/../rz/rz.zip"); // file does not exist
File f2 = new File("T.class"); // file in rz dir under /home/rzhang

// no try/catch block needed
// return "/home/jc/../rz/rz.zip" always
System.out.println("Absolute path for f1: " + f1.getAbsolutePath());
// return "/home/rzhang/rz/T.class"
System.out.println("Absolute path for f2: " + f2.getAbsolutePath());

try {
// not compilable if neither try/catch block nor throws present
// return "/home/rz/rz.zip"
System.out.println("Canonical path for f1: " + f1.getCanonicalPath());

// return "/home/rzhang/rz/T.class"
System.out.println("Canonical path for f2: " + f2.getCanonicalPath());
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}

public static void main(String[] args){
T.testPath();
}
}

7. Which one of the following will create an InputStreamReader correctly?

  1. new InputStreamReader(new FileInputStream("data"));

  2. new InputStreamReader(new FileReader("data"));

  3. new InputStreamReader(new BufferedReader("data"));

  4. new InputStreamReader("data");

  5. new InputStreamReader(System.in);

A:

The leagal constructors for InputStreamReader are
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String enc)

  1. If you compile this line without a try/catch block, you will get a compile error: Exception java.io.FileNotFoundException must be caught, or it must be declared in the throws clause of this method.

    How to do it correctly?

    try {
    new InputStreamReader(new FileInputStream("data"));
    }
    catch (java.io.FileNotFoundException fnfe) {
    }

    Answer: If they let you choose one, choose e. If they let you choose two, choose a and e.

  2. Error #1: FileReader is not an InputStream.
    Error #2: The same problems as a), Exception java.io.FileNotFoundException must be caught

  3. Error #1: BufferedReader is not an InputStream. Error #2: There is no contructor of BufferedReader to take string as argument.

  4. String "data" is not an InputStream.

  5. Correct, since System.in is an InputStream.

8. Why only read() methods in ByteArrayInputStream does not throw IOException?

A: You are right, read() methods of all other InputStreams throw IOException except ByteArrayInputStream.

This is because the entire byte array is in memory; there is no circumstance in which an IOException is possible.

However, close() and reset() methods of ByteArrayInputStream still can throw IOException.

9. How does InputStream.read() method work? Can you give me some sample code?

A:Here is the sample code; the explanation is in the comments. Make sure you compile it, run it, and try to understand it.

// TestRead.java
import java.io.*;
public class TestRead {
public static void main(String argv[]) {
try {
byte[] bary = new byte[]{-1, 0, 12, 23, 56, 98, 23, 127, -128};
ByteArrayInputStream bais = new ByteArrayInputStream(bary);
System.out.print("{ ");
while (test(bais)){
System.out.print(", ");
}
System.out.println(" }");
// output: { 255, 0, 12, 23, 56, 98, 23, 127, 128, -1 }
// Notice 2 negative byte value becomes positive
// -1 is added to the end to signal EOF.
}
catch (IOException e) {
System.out.println(e);
}
}
public static boolean test(InputStream is) throws IOException {
// Read one byte at a time and
// put it at the lower order byte of an int
// That is why the int value will be always positive
// unless EOF, which will be -1
int value = is.read();
System.out.print(value);

// return true as long as value is not -1
return value == (value & 0xff);
}
}

10. How to read data from socket? What is the correct selection for the question?

   A socket object (s) has been created and connected to a standard Internet service
on a remote network server.
Which of the following gives suitable means for reading ASCII data,
one line at a time from the socket?
A. s.getInputStream();
B. new DataInputStream(s.getInputStream());
C. new ByteArrayInputStream(s.getInputStream());
D. new BufferedReader(new InputStreamReader(s.getInputStream()));
E. new BufferedReader(new InputStreamReader(s.getInputStream()),"8859-1");

A:

   A. InputStream does not readLine()
B. DataInputStream.reaLine() deprecated
C. ByteArrayInputStream does not readLine()
D. the only correct answer.
E. encoding put in the wrong place. The correct way is
new BufferedReader(new InputStreamReader(s.getInputStream(), "8859-1"));

See sample from the Sun: Reading from and Writing to a Socket

11.How to use ObjectOutputStream/ObjectInputStream?

A:

A sample code here, which writes to ObjectOutputStream, and reads it back from ObjectInputStream. The program not only deals with instance object, but also Class object. In addition, it uses reflection to analyze how it works.

Find it at TestSerialization.java Pretty heavy i/o, serialization, reflection, transient/static stuff, if it is too over your head, skip it.

12. How to compare two (binary/not) files to see if they are identical?

A:

1) Open 2 streams
2) Compare their length first, if not the same, done
3) If the same lengths, then compare byte to byte, until you find anything not the same, or end-of-file
4) You get your answer

13. When I use the following code to write to a file, why the file has no data in it?

// WriteFile.java
import java.io.*;
public class WriteFile {
public static void main(String[]args)throws Exception {
FileOutputStream fos = new FileOutputStream("out.txt");
PrintWriter pw = new PrintWriter(fos);
pw.print(true);
pw.println("short content file");
}
}

A:

When you open out.txt, it is an empty file, correct. Try to write a lot of text on to the file, and then you get something back, but not all of them.

Why? The reason is for efficiency, the JVM or OS tries to buffer the data to reduce the hit of hard disk or other media. If you do not flush and close, the data might be lost.

I remember when I was coding in Pascal (C?), I had exact the same problem. I learned a lesson that always closing you file or stream after finishing read/write to it.

If you change you code to the forlowing, everything will be ok!

// WriteFile.java
import java.io.*;
public class WriteFile {
public static void main(String[]args)throws Exception {
FileOutputStream fos = new FileOutputStream("out.txt");
PrintWriter pw = new PrintWriter(fos);
pw.print(true);
pw.println("short content file");
pw.close();
fos.close();
}
}

Garbage Collection

14. Will finalize method of all objects eventually be called?

A: The answer is yes, with an exception of JVM being killed abruptly for internal or external reasons.

If the your application is terminated normally, the finalize method of all objects eventually will be called. The simlest way to prove it would be writing a very small application with a few objects instantialized. All objects in your application have a finalize method with a println("XXX object finalize method is called now."); in it. Run it and see the result. This is because JVM will take care of it before normal exit. All objects are eligible for GC and will be GCed before JVM terminates. Of course, we are not considering the special case that JVM might have a bug. :)

However, what is the exception?
  • JVM is killed internally, by

    1. System.exit(1);

    2. Uncaught Exception being thrown at the top level.

    3. You may add more...

  • JVM is killed externally, by

    1. User use ctrl C or other system commands to kill it on windows, unix, or ...

    2. System power off.

    3. You may add more...

15. Any class that includes a finalize method should invoke its superclass' finalize method, why?

A:

The point is that finalize methods are not automatically "chained" - if you subclass a class that has an important finalize, your finalize method should call it. Obviously if you don't know what the superclass finalize method does, you should call it anyway, just to be safe.

By contrast, When you create an object with the new keyword, the superclass constructor(s) are called first. This is automatically "chained".

16. When an object becomes eligible for garbage collection?

A:

The object is no longer referenced or referenced only by objects, which are eligible for GC.An object becomes eligible for garbage collection when there is no way for any active thread to reach that object through a reference or chain of references. (An equivalent answer by Jim Yingst)Set all references to an object to null is sufficient for an object eligible to GC, but not necessary.

Here are two simple examples with proper comments:

public class Test1{
public static void main(String[] args) {
Object a = new Object();
Object b = a;
a = null;
// the Object is still referred by b.
// which is not eligible for garbage collection.

// an infinite loop here
int i = 0;
while (true){
i = i++;
}
//Using ctrl C to kill it, sorry!
}
}

public class Test2{
public static void main(String[] args) {
Object[] ary = new Object[5];
for (int i=0; i<5; i++) {
ary[i] = new Object();
}

// do something here

ary = null;
//Now all objects in the array are eligible for GC
// even none of their references are null.
}
}

17. Can circular reference prevent objects from be garbage collected?

A: No! Prove by counter example:

class Test1 {
public static void main(String arg[]) throws Exception{

MyObj a = new MyObj("a");
MyObj b = new MyObj("b");

//circular reference here
a.o = b;
b.o = a;

a = null;
b = null;
// a and b are both eligible for GC now

MyObj c = new MyObj("c");
c.o = new MyObj("d"); //when c dies, d dies too.
c = null;

// an infinite loop here
// use ^c to kill it

MyObj[] objAry = new MyObj[1024];
int i = 0;
while (true){
// suggest JVM to GC
System.gc();

// use more memory here
i %= 1024;
objAry[i] = new MyObj("X" + i);

i++;
Thread.sleep(5); // Give CPU some breath time
}
}
}

class MyObj {
MyObj o;
String s;
long[] ary = new long[4096]; // make MyObj big

MyObj(String s) {
this.s = s;
}

protected void finalize() throws Throwable {
// Make GC visible
System.out.println(s + ": I am dying");
super.finalize();
}
}

18. How many objects are eligible for GC in the following code after d = null?

public class Test{
public static void main(String[] args) {
Object a = new Object(); // the object original referenced by object reference a
Object b = new Object();
Object c = new Object();
Object d = new Object();

d=c=b=a;
d=null;
}
}

A:

Just remember that operator = is right associate, and then you should be able to figure out the answer by yourself. The equivalent statement is d=(c=(b=a)); The example in here following can be used to get the answer you need too, minor change required.

Answer: Three.
1) After b=a, the object original referenced by b is eligible for GC.
2) After c=(b=a), the object original referenced by c is eligible for GC.
3) After d=(c=(b=a)), the object original referenced by d is eligible for GC.
4) After d=null, nothing new is eligible for GC.
5) The object original referenced by a is not eligible for GC, since it is still referred by references a, b, c. 6) Make sure you understand the differences between physical object and object reference (pointer to object).

19. In garbage collection mechanism, what is vendor/platform dependent? What is not?

A:

How GC implemented is vender and platform dependent. Which means:

It is vender and platform dependent that when and in what order the eligible for GC objects will be GCed.

However, which objects are eligible for GC is independent of implementations. Different vendor may use different algorithms. What algorithm used to find the objects, which are eligible for GC does not matter. What really matters is that they use the same principle.

The object is no longer referenced or referenced only by objects, which are eligible for GC.

Unless they have a bug...

20.Can an object be garbage collected, but a field of it is still alive?

A: Sure, as long as it is still referred by something.

Actually, this is used by many design patterns, e.g. Factory Method pattern. See the following example, read the comments carefully!

// UseSimple.java
class Simple {
void writeSomething(String msg) {
System.out.println("Simple.writeSomething: " + msg);
}

protected void finalize()throws Throwable{
System.out.println("Finalize:Simple");
super.finalize();
}
}

class CombineSimple{
private Simple simFld;

Simple getSimpleField() {
if( simFld == null ) {
simFld = new Simple();
}
return simFld;
}
protected void finalize()throws Throwable{
System.out.println("Finalize:CombineSimple");
super.finalize();
}
}

public class UseSimple {
public static void main(String[] args) {
CombineSimple csObj = new CombineSimple();
Simple simObj = csObj.getSimpleField();

csObj = null;

// Since GC cannot be forced
// we make sure csObj is GCed.
System.gc();
for (int i=0; i<3; i++){
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
System.gc();
}

// The simFld field of csObj will be still alive
// since it is still referred by simObj
simObj.writeSomething("I am still alive!");
}
}

21. What is mark and sweep garbage collection algorithm, is there other algorithms?

A:

The question is out of the scope of SCJP, however, it will help you in job-hunting process. Here is a beautiful applet, which will give you the basics, and have fun: Heap of Fish, A Simulation of a Garbage-Collected Heap