Java多线程编程教程

Java的多线程编程教程

1- 线程的操作原理

Java多线程编程教程_第1张图片

2- 线程入门实例

这个例子中我们需要两个类参与:
  • HelloMain是含有main方法的类,它是一个主线程。
  • HelloThread是一个继承自 Thread 类的类。它被创建并启用到主线程流内运行,并且将平行于主线程运行。
    Java多线程编程教程_第2张图片
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 类的结果如下:
Java多线程编程教程_第3张图片

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 类:
Java多线程编程教程_第4张图片

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);
为了便于理解,我们考虑下面的例子。下面的三个类已经介入实例:
Java多线程编程教程_第5张图片
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多线程编程教程_第6张图片
上图显示,当一切正常的线程停止,虽然其代码是无限运行的,但是守护线程也已停止。

守护线程使用来做什么?
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;
考虑下面的一个例子:
Java多线程编程教程_第7张图片
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的结果:
Java多线程编程教程_第8张图片
使用 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");
   }

}
运行示例的结果:
Java多线程编程教程_第9张图片

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...");
   }

}
运行示例的结果:
Java多线程编程教程_第10张图片

7- 使用yield()

从理论上讲,“yield”是指放手,放弃,投降。让步线程告诉虚拟机,它的愿意让其他线程在它的位置进行调度。则表示它没有太关键事情做了。 请注意,这只是一个暗示,不能保证有任何效果。

yield()被定义为在 Thread.java 中如下:
public static native void yield();

你可能感兴趣的:(java基础)