Java的多线程编程教程
1- 线程的操作原理

2- 线程入门实例
这个例子中我们需要两个类参与:
-
HelloMain是含有main方法的类,它是一个主线程。
- HelloThread是一个继承自 Thread 类的类。它被创建并启用到主线程流内运行,并且将平行于主线程运行。

package com.yiibai.tutorial.thread.hellothread;
public class HelloMain {
public static void main(String[] args) throws InterruptedException {
int idx = 1;
for (int i = 0; i < 2; i++) {
System.out.println("Main thread running " + idx++);
// Sleep 2101 miliseconds.
Thread.sleep(2101);
}
HelloThread helloThread = new HelloThread();
// Run thread
helloThread.start();
for (int i = 0; i < 3; i++) {
System.out.println("Main thread running " + idx++);
// Sleep 2101 miliseconds.
Thread.sleep(2101);
}
System.out.println("==> Main thread stopped");
}
}
HelloThread.java
package com.yiibai.tutorial.thread.hellothread;
public class HelloThread extends Thread {
// Code of method run() will be executed when
// thread call start()
@Override
public void run() {
int index = 1;
for (int i = 0; i < 10; i++) {
System.out.println(" - HelloThread running " + index++);
try {
// Sleep 1030 miliseconds.
Thread.sleep(1030);
} catch (InterruptedException e) {
}
}
System.out.println(" - ==> HelloThread stopped");
}
}
运行 HelloMain 类的结果如下:


3- Runnable接口
您也可以从一个类来实现Runnable接口来创建一个线程。见例子:
RunnableDemo.java
package com.yiibai.tutorial.thread.runnable;
public class RunnableDemo implements Runnable {
@Override
public void run() {
int idx = 1;
for (int i = 0; i < 5; i++) {
System.out.println("Hello from RunnableDemo " + idx++);
// Sleep 2 second.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
RunnableTest.java
package com.yiibai.tutorial.thread.runnable;
public class RunnableTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("Main thread running..");
// Create a thread from Runnable.
Thread thread = new Thread(new RunnableDemo());
thread.start();
// Sleep 5 seconds.
Thread.sleep(5000);
System.out.println("Main thread stopped");
}
}
运行 RunnableTest 类:


4- 守护线程
Java的线程划分为2种类型:正常线程和守护线程。两者不同的是其结束的方式。在程序中,正常的线程和守护线程各自并行运行。当一切正常线程完成,所有的守护线程也将被终止。注:使用 setDeamon(boolean) 建立一个线程,可以设置其是或不是守护线程。 值得注意的是,只能在当线程尚未运行时调用setDeamon(boolean)。这意味着,当线程已经运行,就不能再从非守护线程改变为守护进程,反之亦然。
当创建一个新的线程,它继承了其父线程守护功能。因此,当你从一个类的main方法创建线程,该线程自然就是非守护使线程。因此,如果在一个守护线程创建一个新的线程,默认情况下它也是守护线程。
Thread thread = new MyThread(); // marks this thread as a daemon thread // This method is only called when the thread is not a start. // In the case of start, it will be throws an exception. thread.setDeamon(true); // marks this thread as a none-daemon thread // This method is only called when the thread is not a start. // In the case of start, it will be throws an exception. thread.setDeamon(false);
为了便于理解,我们考虑下面的例子。下面的三个类已经介入实例:


NoneDeamonThread.java
package com.yiibai.tutorial.thread.deamon;
public class NoneDeamonThread extends Thread {
@Override
public void run() {
int i = 0;
// Loop 10 times. This thread will end.
while (i < 10) {
System.out.println(" - Hello from None Deamon Thread " + i++);
try {
// Sleep 1 second
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
// None deamon thread ending.
System.out.println("\n==> None Deamon Thread ending\n");
}
}
DeamonThread.java
package com.yiibai.tutorial.thread.deamon;
class DeamonThread extends Thread {
@Override
public void run() {
int count = 0;
// Infinite loop
while (true) {
System.out.println("+ Hello from Deamon Thread " + count++);
try {
// Sleep 2 second
sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
DaemonTest.java
package com.yiibai.tutorial.thread.deamon;
public class DaemonTest {
public static void main(String[] args) {
System.out.println("==> Main Thread running..\n");
// Create thread
Thread deamonThread = new DeamonThread();
// Set deamon true
deamonThread.setDaemon(true);
deamonThread.start();
// Create other thread
new NoneDeamonThread().start();
try {
// Sleep 5 second
Thread.sleep(5000);
} catch (InterruptedException e) {
}
// Main Thread ending
System.out.println("\n==> Main Thread ending\n");
}
}
运行类 DeamonTest:


上图显示,当一切正常的线程停止,虽然其代码是无限运行的,但是守护线程也已停止。
守护线程使用来做什么?
Java一个重要守护线程是垃圾收集线程。这意味着收集资源中不再使用解放出来的内存。当所有用户线程停止运行,垃圾收集线程也会停止。
5- 使用join() & join(long)
Thread.join()是一个方法通知父线程等待在继续运行之前要完成这个线程。
// Parent thread must wait until the end of this thread, before being continued. // (This is equivalent to calling join(0)) public final void join() throws InterruptedException; // Parent thread must wait 'millis' milliseconds to continue running. // After call join(long). // If the parameter millis = 0 means to wait until the end of this thread. public final synchronized void join(long millis) throws InterruptedException; // Parent thread must wait 'millis' milliseconds and 'nanos' nanoseconds to continue running. // After call join(long,int). // 1 second = 1000000 nanoseconds. public final synchronized void join(long millis, int nanos) throws InterruptedException;
考虑下面的一个例子:


JoinThread.java
package com.yiibai.tutorial.thread.join;
public class JoinThread extends Thread {
private String threadName;
private int count;
public JoinThread(String threadName, int count) {
this.threadName = threadName;
this.count = count;
}
@Override
public void run() {
for (int i = 1; i < count + 1; i++) {
System.out.println("Hello from " + this.threadName + " " + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("\n==> Thread " + threadName + " end!\n");
}
}
JoinTest.java
package com.yiibai.tutorial.thread.join;
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("\n==> Main thread starting..\n");
Thread joinThreadA = new JoinThread("A*", 2);
Thread joinThreadB = new JoinThread("B*", 3);
// None join Thread.
Thread noJoinThreadC = new JoinThread("C", 5);
joinThreadA.start();
joinThreadB.start();
noJoinThreadC.start();
// Using join()
joinThreadA.join();
joinThreadB.join();
// The following code will have to wait until 2
// JoinThread A, B completed.
System.out.println("Hello from main thread...");
System.out.println("Thread A isLive? " + joinThreadA.isAlive());
System.out.println("Thread B isLive? " + joinThreadB.isAlive());
System.out.println("Thread C isLive? " + noJoinThreadC.isAlive());
System.out.println("\n==> Main Thread end!\n");
}
}
运行JoinTest的结果:


使用 join(long millis) 的例子:
JoinTest2.java
package com.yiibai.tutorial.thread.join;
public class JoinTest2 {
public static void main(String[] args) throws InterruptedException {
System.out.println("\n==> Main thread starting..\n");
Thread joinThreadA = new JoinThread("A*", 5);
joinThreadA.start();
// Main thread must wait to 5000 miliseconds,
// and then continue running. (Not necessarily joinThreadA finish)
joinThreadA.join(5000);
System.out.println("Main thread after 5000 milli second");
System.out.println("Hello from main thread...");
System.out.println("Thread A isLive? " + joinThreadA.isAlive());
System.out.println("\n==> Main Thread end!\n");
}
}
运行示例的结果:


6- 处理线程异常
Thread.setDefaultUncaughtExceptionHandler()方法设置默认处理程序,当一个线程突然终止由于未捕获到异常出现时调用该程序,并且没有其他的处理程序已经为该线程定义。
ThreadExceptionDemo.java
package com.yiibai.tutorial.thread.exception;
import java.util.Random;
public class ThreadExceptionDemo {
public static class RunnableTest implements Runnable {
@Override
public void run() {
System.out.println("Thread running ..");
while (true) {
Random r = new Random();
// A random number from 0-99
int i = r.nextInt(100);
System.out.println("Next value " + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
if (i > 70) {
// Simulate an exception was not handled in the thread.
throw new RuntimeException("Have a problem...");
}
}
}
}
public static void main(String[] args) {
System.out.println("==> Main thread running...");
Thread thread = new Thread(new RunnableTest());
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("#Thread: " + t);
System.out.println("#Thread exception message: " + e.getMessage());
}
});
thread.start();
System.out.println("==> Main thread end...");
}
}
运行示例的结果:


7- 使用yield()
从理论上讲,“yield”是指放手,放弃,投降。让步线程告诉虚拟机,它的愿意让其他线程在它的位置进行调度。则表示它没有太关键事情做了。 请注意,这只是一个暗示,不能保证有任何效果。
yield()被定义为在 Thread.java 中如下:
public static native void yield();

1万+

被折叠的 条评论
为什么被折叠?



