1、Thread 类的join() 方法
当前线程调用某个线程的这个方法时,它会暂停当前线程,直到被调用线程执行完成。
例子:
public class DataSourcesLoader implements Runnable{ @Override public void run() { System.out.println(" ---Begin DataSourcesLoader ---" ); try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException ex) { Logger.getLogger(DataSourcesLoader.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(" ---End DataSourcesLoader ---" ); } public static void main(String[] args) { System.out.println(" ---Begin Main ---" ); Thread t = new Thread(new DataSourcesLoader()); t.start(); try { t.join(); } catch (InterruptedException ex) { Logger.getLogger(DataSourcesLoader.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(" ---End Main ---" ); } }
输出为:
run:
---Begin Main ---
---Begin DataSourcesLoader ---
---End DataSourcesLoader ---
---End Main ---
BUILD SUCCESSFUL (total time: 4 seconds)
保证了 在t进程完成之后,main进程再完成。
2、守护线程setDaemon
当守护线程是程序里唯一在运行的线程时,JVM会结束守护线程并终止程序。
只能在start() 方法之前可以调用 setDaemon() 方法。一旦线程运行了,就不能修改守护状态。
可以使用 isDaemon() 方法来检查线程是否是守护线程(方法返回 true) 或者是使用者线程 (方法返回 false)
3、UncaughtExceptionHandler 接口
可以在线程里处理不受控制的异常
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("Thread:" + t.getId()); System.out.println("Thread status:" + t.getState()); System.out.println("Exception:" + e.getMessage()); System.out.println("Exception Stack Trace: "); e.printStackTrace(System.out); } public static void main(String[] args) { Thread t = new Thread(new MyTask()); t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); t.start(); } } class MyTask implements Runnable { @Override public void run() { System.out.println("----- start MyTask -----"); if (true) { throw new RuntimeException("HAHAHAHHAHAHA"); } System.out.println("----- end MyTask -----"); } }
输出
----- start MyTask -----
Thread:9
Thread status:RUNNABLE
Exception:HAHAHAHHAHAHA
Exception Stack Trace:
java.lang.RuntimeException: HAHAHAHHAHAHA
at chapter1.MyTask.run(MyUncaughtExceptionHandler.java:37)
at java.lang.Thread.run(Thread.java:744)
BUILD SUCCESSFUL (total time: 0 seconds)
4、线程工厂ThreadFactory 生成线程
ThreadFactory 有一个方法: public Thread newThread(Runnable r)
public class MyThreadFactory implements ThreadFactory { private int counter; private String name; private List<String> stats; public MyThreadFactory(String name) { counter = 0; this.name = name; stats = new ArrayList<String>(); } @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, name + "-Thread_" + counter); counter++; stats.add(String.format("created thread %d with name %s on %s ", t.getId(), t.getName(), new Date())); return t; } public String getStats() { StringBuffer buffer = new StringBuffer(); Iterator<String> it = stats.iterator(); while (it.hasNext()) { buffer.append(it.next()); buffer.append(" "); } return buffer.toString(); } public static void main(String[] args) { MyThreadFactory factory = new MyThreadFactory("MyThreadFactory"); Task task = new Task(); Thread thread; System.out.printf("Starting the Threads "); for (int i = 0; i < 10; i++) { thread = factory.newThread(task); thread.start(); } System.out.printf("Factory stats: "); System.out.printf("%s ", factory.getStats()); } } class Task implements Runnable { @Override public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }
5、线程中断 interrupt
public class InterruptTest { public static void main(String[] args) { Thread task = new PrimeGenerator(); task.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } task.interrupt(); } } class PrimeGenerator extends Thread { @Override public void run() { long number = 1L; while (true) { if (isPrime(number)) { System.out.printf("Number %d is Prime", number); } if (isInterrupted()) { System.out.printf("The Prime Generator has been Interrupted"); return; } number++; } } private boolean isPrime(long number) { if (number <= 2) { return true; } for (long i = 2; i < number; i++) { if ((number % i) == 0) { return false; } } return true; } }
isInterrupted()和interrupted() 方法有着很重要的区别:
第一个不会改变interrupted属性值,但是第二个会设置成false。
interrupted() 方法是一个静态方法,建议使用isInterrupted()方法。
5、线程中断 InterruptException
如果线程实现的是由复杂的算法分成的一些方法,或者它的方法有递归调用,那么我们可以用更好的机制来控制线程中断。为了这个Java提供了InterruptedException异常。当你检测到程序的中断并在run()方法内捕获,你可以抛这个异常。
public class InterruptExceptionTest { public static void main(String[] args) { FileSearch searcher = new FileSearch("C:\", "autoexec.bat"); Thread thread = new Thread(searcher); thread.start(); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); } } class FileSearch implements Runnable { private String initPath; private String fileName; public FileSearch(String initPath, String fileName) { this.initPath = initPath; this.fileName = fileName; } @Override public void run() { File file = new File(initPath); if (file.isDirectory()) { try { directoryProcess(file); } catch (InterruptedException e) { System.out.printf("%s: The search has been interrupted", Thread .currentThread().getName()); } } } private void directoryProcess(File file) throws InterruptedException { File list[] = file.listFiles(); if (list != null) { for (int i = 0; i < list.length; i++) { if (list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } if (Thread.interrupted()) { throw new InterruptedException(); } } private void fileProcess(File file) throws InterruptedException { if (file.getName().equals(fileName)) { System.out.printf("%s : %s ", Thread.currentThread().getName(), file.getAbsolutePath()); } if (Thread.interrupted()) { throw new InterruptedException(); } } }