Java教程 第53页
Java线程教程 – Java原子变量 新线程并发包 java.util.concurrent和java.util.concurrent.atomic和java.util.concurrent.locks包括非常有用的并发构造。 线程并发包以四种方式支持并发。 原子变量 锁 同步器 并发集合 原子变量 原子变量类的命名类似于AtomicXxx,例如,AtomicInteger类用于表示一个int变量。 原子变量可用于在不使用任何锁的情况下以原子方式对单个变量执行多个指令。 标量原子变量类 AtomicInteger,AtomicLong和AtomicBoolean类分别支持对原始数据类型int,long和boolean的操作。 当引用变量需要以原子方式更新时,AtomicReference类用于处理引用数据类型。 原子数组类 有三个类称为AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray,它们表示一个int,long和引用类型的数组,其元素可以进行原子性更新。 原子字段更新程序类 有三个类称为AtomicLongFieldUpdater,AtomicIntegerFieldUpdater和AtomicReferenceFieldUpdater,可用于使用反射以原子方式更新类的易失性字段。 要获得对这些类的对象的引用,您需要使用他们的工厂方法newUpdater()。 原子复合变量类 例子 以下代码显示如何使用AtomicLong类来创建计数器。 import java.util.concurrent.atomic.AtomicLong; public class AtomicCounter { private AtomicLong value = new AtomicLong(0L); public long next() { return value.incrementAndGet(); } }
Java线程教程 – Java线程加入 线程可以等待另一个线程死亡或终止。 例子 假设有两个线程,t1和t2。如果线程t1调用t2.join(),线程t1开始等待,直到线程t2终止。 调用t2.join()阻塞直到t2终止。 如果其中一个线程无法继续,直到另一个线程完成执行,在程序中使用join()方法是很有用的。 下面的代码有一个例子,当程序完成执行时,它在标准输出上打印一条消息。 public class Main { public static void main(String[] args) { Thread t1 = new Thread(Main::print); t1.start(); System.out.println("Done."); } public static void print() { for (int i = 1; i <= 5; i++) { try { System.out.println("Counter: " + i); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } 上面的代码生成以下结果。 从结果我们可以看到“完成”。被打印在来自真实线程的消息之前。 t1.start(); 刚刚启动该线程,它会阻断执行,并等待线程完成。 下面的代码使用join()等待线程完成,然后打印“完成”。 public class Main { public static void main(String[] args) { Thread t1 = new Thread(Main::print); t1.start(); try { t1.join(); // "main" thread waits until t1 is terminated } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Done."); } public static void print() { for (int i = 1; i <= 5; i++) { try { System.out.println("Counter: " +...
Java线程教程 – Java线程生命周期 线程总是处于以下六种状态之一: New Runnable Blocked Waiting Timed-waiting Terminated 线程的所有这些状态都是JVM状态。 当一个线程被创建并且它的start()方法还没有被调用时,它处于新的状态。 Thread t = new MyThreadClass(); // t is in the new state 准备运行或运行的线程处于可运行状态。 如果线程尝试输入或重新输入同步的方法或块,但该监视器正在被另一个线程使用,则该线程处于阻塞状态。 状态转换 线程可以通过调用下表中列出的方法将自身置于等待状态。 方法 描述 wait() 从Object类。 join() 从Thread类。 park() 从java.util.concurrent.locks.LockSupport类。调用此方法的线程可以通过调用线程上的unpark()方法等待直到许可可用。 线程可以通过调用下表中列出的方法将自身置于等待等待状态。 描述 描述 sleep() 从Thread类。 wait (long millis)wait(long millis, int nanos) 从Object类。 join(long millis)join(long millis, int nanos) 从Thread类。 parkNanos (long nanos)parkNanos (Object blocker, long nanos) 从LockSupport类,它在java.util.concurrent.locks包中。 parkUntil (long deadline)parkUntil (Object blocker, long nanos) 从LockSupport类,它在java.util.concurrent.locks包中。 已完成其执行的线程处于终止状态。 终止的线程不能转换到任何其他状态。 例子 我们可以使用一个线程的isAlive()方法,在它已经启动后,知道它是否存活或终止。 我们可以使用Thread类中的getState()方法来随时获取线程的状态。 此方法返回Thread.State枚举类型的常量之一。 以下代码演示了线程从一个状态到另一个状态的转换。 class ThreadState extends Thread { private boolean keepRunning = true; private boolean wait = false; private Object syncObject = null; public ThreadState(Object syncObject) { this.syncObject = syncObject; } public void run() { while (keepRunning) { synchronized (syncObject) { if (wait) { try {...
Java线程教程 – Java线程优先级 所有线程都有优先级。 优先级由1到10之间的整数表示。 优先级为1的线程优先级最低。优先级为10的线程具有最高优先级。 在Thread类中定义了三个常量来表示下表中列出的三个不同的线程优先级。 线程优先级常量 整数值 MIN_PRIORITY 1 NORM_PRIORITY 5 MAX_PRIORITY 10 具有较高优先级的线程应该有更多的CPU时间。 线程的优先级只是调度器的一个提示。 Thread类的setPriority()方法为线程设置了新的优先级。 getPriority()方法返回线程的当前优先级。 创建线程时,其优先级设置为创建线程的优先级。 例子 以下代码演示如何设置和获取线程的优先级。 public class Main { public static void main(String[] args) { Thread t = Thread.currentThread(); System.out.println("main Thread Priority:" + t.getPriority()); Thread t1 = new Thread(); System.out.println("Thread(t1) Priority:" + t1.getPriority()); t.setPriority(Thread.MAX_PRIORITY); System.out.println("main Thread Priority:" + t.getPriority()); Thread t2 = new Thread(); System.out.println("Thread(t2) Priority:" + t2.getPriority()); // Change thread t2 priority to minimum t2.setPriority(Thread.MIN_PRIORITY); System.out.println("Thread(t2) Priority:" + t2.getPriority()); } } 上面的代码生成以下结果。
Java线程教程 – Java守护线程 线程可以是守护线程或用户线程。 守护线程是服务提供者线程。 当JVM检测到应用程序中的所有线程都只是守护线程时,它将退出应用程序。 我们可以通过使用setDaemon()方法通过传递true作为参数,使线程成为一个守护线程。 我们必须在启动线程之前调用一个线程的setDaemon()方法。否则,一个java.lang。抛出IllegalThreadStateException。 我们可以使用isDaemon()方法来检查线程是否是守护线程。 创建线程时,其守护程序属性与创建线程的线程相同。 例子 以下代码创建一个线程并将线程设置为守护线程。 public class Main { public static void main(String[] args) { Thread t = new Thread(Main::print); t.setDaemon(true); t.start(); System.out.println("Exiting main method"); } public static void print() { int counter = 1; while (true) { try { System.out.println("Counter:" + counter++); Thread.sleep(2000); // sleep for 2 seconds } catch (InterruptedException e) { e.printStackTrace(); } } } } 上面的代码生成以下结果。 例2 以下代码将线程设置为非守护线程。由于这个程序有一个非守护线程,JVM将继续运行应用程序,即使在main()方法完成后。 您必须强制停止此应用程序,因为线程在无限循环中运行。 public class Main { public static void main(String[] args) { Thread t = new Thread(Main::print); t.setDaemon(false); t.start(); System.out.println("Exiting main method"); } public static void print() { int counter = 1; while (true) { try { System.out.println("Counter:" + counter++); Thread.sleep(2000); // sleep for 2 seconds } catch (InterruptedException e) { e.printStackTrace();...
Java线程教程 – Java线程组 线程总是线程组的成员。 默认情况下,线程的线程组是其创建者线程的组。 Java程序中的线程组由java.lang.ThreadGroup类的一个对象表示。 Thread类中的getThreadGroup()方法返回一个线程的ThreadGroup的引用。 例子 以下代码演示了,默认情况下,新线程是其创建者线程的线程组的成员。 public class Main { public static void main(String[] args) { Thread t1 = Thread.currentThread(); ThreadGroup tg1 = t1.getThreadGroup(); System.out.println("Current thread"s name: " + t1.getName()); System.out.println("Current thread"s group name: " + tg1.getName()); Thread t2 = new Thread("my new thread"); ThreadGroup tg2 = t2.getThreadGroup(); System.out.println("New thread"s name: " + t2.getName()); System.out.println("New thread"s group name: " + tg2.getName()); } } 上面的代码生成以下结果。 注意 您还可以创建线程组,并在该线程组中放置一个新线程。 要在你的线程组中放置一个新线程,我们必须使用Thread类的一个构造函数来接受一个ThreadGroup对象作为参数。 以下代码将新线程放置在特定线程组中: ThreadGroup myGroup = new ThreadGroup("My Thread Group"); Thread t = new Thread(myGroup, "myThreadName"); 线程组以树状结构布置。线程组可以包含另一个线程组。 ThreadGroup类中的getParent()方法返回线程组的父线程组。 顶层线程组的父级为null。 ThreadGroup的activeCount()方法返回组中活动线程数的估计值。 ThreadGroup类的enumerate()方法返回线程组中的线程。
Java线程教程 – Java Volatile变量 关键字volatile可以保持线程的工作内存中的变量值与它们在主存储器中的值同步。 我们可以声明一个变量volatile如下: volatile boolean flag = true; 我们可以只声明一个类成员变量,实例或静态字段,作为volatile。 我们可以使用volatile变量作为标志来停止线程。 例子 下面的代码演示了volatile变量的使用。 public class Main extends Thread { private volatile boolean keepRunning = true; public void run() { System.out.println("Thread started"); while (keepRunning) { try { System.out.println("Going to sleep"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Thread stopped"); } public void stopThread() { this.keepRunning = false; } public static void main(String[] args) throws Exception{ Main v = new Main(); v.start(); Thread.sleep(3000); System.out.println("Going to set the stop flag to true"); v.stopThread(); } } 上面的代码生成以下结果。
Java线程教程 – Java线程状态 停止,挂起和恢复线程 下面的代码演示了如何模拟Thread类中的stop(),suspend()和resume()方法。 public class Main extends Thread { private volatile boolean keepRunning = true; private boolean suspended = false; public synchronized void stopThread() { this.keepRunning = false; this.notify(); } public synchronized void suspendThread() { this.suspended = true; } public synchronized void resumeThread() { this.suspended = false; this.notify(); } public void run() { System.out.println("Thread started..."); while (keepRunning) { try { System.out.println("Going to sleep..."); Thread.sleep(1000); synchronized (this) { while (suspended) { System.out.println("Suspended..."); this.wait(); System.out.println("Resumed..."); } } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws Exception { Main t = new Main(); t.start(); Thread.sleep(2000); t.suspendThread(); Thread.sleep(2000); t.resumeThread(); Thread.sleep(2000); t.stopThread(); } } 上面的代码生成以下结果。
Java线程教程 – Java线程休眠 Thread类包含一个静态sleep()方法,它使线程在指定的持续时间内休眠。 Thread.sleep()方法接受超时作为参数。 我们可以指定超时的毫秒数,或毫秒和纳秒。执行此方法的线程将休眠指定的时间。 操作系统调度程序不调度睡眠线程以接收CPU时间。 如果线程在进入休眠之前拥有锁的所有权,则它在休眠期间继续保持这些锁。 sleep()方法抛出java.lang.InterruptedException,你的代码必须处理它。 例子 下面的代码演示了使用Thread.sleep()方法。 public class Main { public static void main(String[] args) { try { System.out.println("sleep for 5 seconds."); Thread.sleep(5000); // The "main" thread will sleep System.out.println("woke up."); } catch (InterruptedException e) { System.out.println("interrupted."); } System.out.println("done."); } } 上面的代码生成以下结果。 例2 java.util.concurrent包中的TimeUnit枚举表示各种单位(如毫秒,秒,分钟,小时,天等)的时间测量值。 它有sleep()方法,其工作方式与Thread.sleep()相同。 我们可以使用TimeUnit的sleep()方法来避免持续时间转换: TimeUnit.SECONDS.sleep(5); // Same as Thread.sleep(5000); 完整的源代码 import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) { try { System.out.println("sleep for 5 seconds."); TimeUnit.SECONDS.sleep(5); // Same as Thread.sleep(5000); // The "main" thread will sleep System.out.println("woke up."); } catch (InterruptedException e) { System.out.println("interrupted."); } System.out.println("done."); } } 上面的代码生成以下结果。
Java线程教程 – Java当前线程 一个语句可以由不同的线程在不同的时间执行。 Thread类静态方法currentThread()返回调用此方法的Thread对象的引用。 考虑下面的语句: Thread t = Thread.currentThread(); 该语句将执行上述语句的线程对象的引用分配给变量t。 例子 下面的代码演示了如何使用currentThread()方法。 两个不同的线程调用CurrentThread类的run()方法中的Thread.currentThread()方法。 该程序只打印正在执行的线程的名称。 public class Main extends Thread { public Main(String name) { super(name); } @Override public void run() { Thread t = Thread.currentThread(); String threadName = t.getName(); System.out.println("Inside run() method: " + threadName); } public static void main(String[] args) { Main ct1 = new Main("First Thread"); Main ct2 = new Main("Second Thread"); ct1.start(); ct2.start(); Thread t = Thread.currentThread(); String threadName = t.getName(); System.out.println("Inside main() method: " + threadName); } } 上面的代码生成以下结果。 当你运行一个类时,JVM启动一个名为main的线程,它负责执行main()方法。 处理线程中未捕获的异常 我们可以处理线程中抛出的未捕获异常。 它使用实现java.lang.Thread.UncaughtExceptionHandler接口的类的对象来处理。 接口被定义为Thread类中的嵌套静态接口。 下面的代码显示了一个类,它可以用作线程的未捕获异常处理程序。 class CatchAllThreadExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught Exception from Thread:" + t.getName()); } } public class Main { public static void main(String[] args) {...