Here I would like to list some concepts I used to be not aware of.
Daemon threads are service providers for other threads running in the same process as the daemon thread. The run() method for a daemon thread is typically an infinite loop that waits for a service request.
When the only remaining threads in a process are daemon threads, the interpreter exits. This makes sense because when only daemon threads remain, there is no other thread for which a daemon thread can provide a service.
Any Java thread can be a daemon thread. To specify that a thread is a daemon thread, call the setDaemon method with the argument true. To determine if a thread is a daemon thread, use the accessor method isDaemon.
When a Java thread is created, it inherits its priority from the thread that created it. You can also modify a thread's priority at any time after its creation using the setPriority method. Thread priorities are integers ranging between MIN_PRIORITY and MAX_PRIORITY (constants defined in the Thread class). The higher the integer, the higher the priority.
At any given time, when multiple threads are ready to be executed, the runtime system chooses the runnable thread with the highest priority for execution. Only when that thread stops, yields, or becomes not runnable for some reason will a lower priority thread start executing. If two threads of the same priority are waiting for the CPU, the scheduler chooses one of them to run in a round-robin fashion. The chosen thread will run until one of the following conditions is true:
Then the second thread is given a chance to run, and so on, until the interpreter exits.
In some Threads, there could be a while(true) condition block to execute some behavior infiity. For example:
public int token = 1; public void run() { while (token < n) { token++; } }
The while loop in the run method is in a tight loop. Once the scheduler chooses a thread with this thread body for execution, the thread never voluntarily relinquishes control of the CPU--the thread continues to run until the while loop terminates naturally or until the thread is preempted by a higher priority thread. This thread is called a selfish thread.
In some situations, having selfish threads doesn't cause any problems because a higher priority thread preempts the selfish one (just as the drawing thread in the RaceApplet preempts the selfish runners). However, in other situations, threads with CPU-greedy run methods, such as the Runner class, can take over the CPU and cause other threads to wait for a long time before getting a chance to run.
Time-slicing comes into play when there are multiple "Runnable" threads of equal priority and those threads are the highest priority threads competing for the CPU.
The Java runtime does not implement (and therefore does not guarantee) time-slicing. However, some systems on which you can run Java do support time-slicing. Your Java programs should not rely on time-slicing as it may produce different results on different systems.
In order to run a Object's method, Thread should acquire the monitor of this object.
A monitor is associated with a specific data item (a condition variable) and functions as a lock on that data. When a thread holds the monitor for some data item, other threads are locked out and cannot inspect or modify the data.
The code segments within a program that access the same data from within separate, concurrent threads are known as critical sections. In the Java language, you mark critical sections in your program with the synchronized keyword.
Both notifyAll and wait are members of the java.lang.Object class. The notifyAll and wait methods can be invoked only by the thread that holds the lock.
We use wait in conjunction with notify or notifyAll to coordinate the activities of multiple threads using the same resources.
When the thread enters the wait method, the monitor is released atomically, and when the thread exits the wait method, the monitor is acquired again. This gives the waiting object the opportunity to acquire the monitor and, depending on who's waiting, resume the pending operations again.
notifyAll() wakes up the thread that is waiting to get the object's monitor.
notify() arbitrarily wakes up one of the threads waiting on the monitor. In this situation, each of the remaining waiting threads continues to wait until the monitor is relinquished and it is chosen by the runtime system. The use of notify can be ill-conditioned, that is, it can fail when the conditions are changed just a little. Solutions based on notifyAll tend to be more robust. A programmer who is not going to analyze a multi-threaded program sufficiently carefully is better off using notifyAll().
Besides using these timed wait methods to synchronize threads, you can also use them in place of sleep. Both methods delay for the requested amount of time, but you can easily wake up wait with a notify. The thread can then see immediately that it should go away. This doesn't matter too much for threads that don't sleep for long, but it could be important for threads that sleep for minutes at a time.
I put the java source code demo to help memory recovery in future.
Resource.java:
/** * @author wgu * */ public class Resource { private int content = 0; private boolean signal = false; public synchronized int get() { while (!signal) { try { wait(); } catch (InterruptedException e) { } } signal = false; notifyAll(); return content; } public synchronized void put(int i) { while (signal) { try { wait(); } catch (InterruptedException e) { } } signal = true; content = i; notifyAll(); } }
Producer.java:
public class Producer extends Thread { int times; int id; Resource data; public Producer(Resource data, int times) { this(0, data, times); } public Producer(int id, Resource data, int times) { this.times = times; this.data = data; this.id = id; } public void run() { for (int i = 0; i < times; i++) { System.out.println("Producer #" + id + " put: " + i); data.put(i); try { // to make sure the output displayed sequentely Thread.sleep(1000); } catch (InterruptedException e) { } } } }
Consumer.java:
/** * @author wgu * */ public class Consumer extends Thread { int times; int id; Resource data; public Consumer(Resource data, int num) { this(0, data, num); } public Consumer(int id, Resource data, int num) { this.times = num; this.data = data; this.id = id; } public void run() { for (int i = 0; i < times; i++) { System.out.println("Consumer #" + id + " get: " + data.get()); } } }
Test application, Main.java:
public class Main { /** * @param args */ public static void main(String[] args) { Resource data = new Resource(); Producer p0 = new Producer(data, 10); Consumer c0 = new Consumer(data, 10); Resource data1 = new Resource(); Producer p1 = new Producer(1, data1, 10); Consumer c1 = new Consumer(1, data1, 10); p0.start(); c0.start(); p1.start(); c1.start(); } } //The output will be. Order could be different in different machine. Producer #0 put: 0 Consumer #0 get: 0 Producer #1 put: 0 Consumer #1 get: 0 Producer #1 put: 1 Consumer #1 get: 1 Producer #0 put: 1 Consumer #0 get: 1 Producer #0 put: 2 Consumer #0 get: 2 Producer #1 put: 2 Consumer #1 get: 2 Producer #0 put: 3 Consumer #0 get: 3 Producer #1 put: 3 Consumer #1 get: 3 Producer #0 put: 4 Consumer #0 get: 4 Producer #1 put: 4 Consumer #1 get: 4 Producer #0 put: 5 Producer #1 put: 5 Consumer #0 get: 5 Consumer #1 get: 5 Producer #1 put: 6 Producer #0 put: 6 Consumer #1 get: 6 Consumer #0 get: 6 Producer #0 put: 7 Producer #1 put: 7 Consumer #1 get: 7 Consumer #0 get: 7 Producer #0 put: 8 Producer #1 put: 8 Consumer #0 get: 8 Consumer #1 get: 8 Producer #1 put: 9 Consumer #1 get: 9 Producer #0 put: 9 Consumer #0 get: 9
During synchronization implementation, we could meet the problem there is no synchronization. It could happen in many cases:
public /*synchronized*/ int get() { while (!signal) { try { wait(); } catch (InterruptedException e) { } } signal = false; notifyAll(); return content; } public /*synchronized*/ void put(int i) { while (signal) { try { wait(); } catch (InterruptedException e) { } } signal = true; content = i; notifyAll(); }
Producer #0 put: 0 Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread not owner at java.lang.Object.notifyAll(Native Method) at com.gemalto.wgu.threads.test.Resource.put(Resource.java:29) at com.gemalto.wgu.threads.test.Producer.run(Producer.java:23) java.lang.IllegalMonitorStateException: current thread not owner at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Unknown Source) at com.gemalto.wgu.threads.test.Resource.get(Resource.java:11) at com.gemalto.wgu.threads.test.Consumer.run(Consumer.java:22)
To avoid a no-synchronization scenario, choose an object common to all relevant threads. That way, those threads compete to acquire the same object's lock, and only one thread at a time can enter the associated critical code section.
I list here the java source code from java.lang.Thread.join(int):
/** * Waits at most <code>millis</code> milliseconds for this thread to die. A * timeout of <code>0</code> means to wait forever. * * @param millis * the time to wait in milliseconds. * @exception InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is cleared * when this exception is thrown. */ public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
JVM cannot detect or prevent deadlock.
During multiple synchronized threads programming, we should provent "deadlock". For example, Both ThreadA and ThreadB needs monitros of resource1 and resource2, in case ThreadA acquire monitor of resource1 and ThreadB acquires monitor of resource2 in same time, they will be queued to waiting for the monitor release of the other.
Multiple processor in socketserver side to process multiple socket client.
This implementation comes before JDK1.5. From JDK1.5, we can use ThreadPoolExecutor to execute tasks which will process client requests.
Object.wait() and Object.notifyAll() to monitor Driver Status in DriverManager. Only after making sure all Drivers are shutdown properly, DriverManager could be cleaned.