Java多线程实现

来源:互联网 发布:前端网页ajax获取数据 编辑:程序博客网 时间:2024/06/07 03:15

PART.1  通过Thread实现多线程

 

1. Thread

 

getID()

获取线程ID

getName(), setName()

获取和设置线程名。

getPriority(),  setPriority()

获取和设置线程优先级。

getState()

获取线程状态。

getThreadGroup()

获取线程所在的线程组。

isAlive()

获取线程是否已经启动并且没有终止。

isDaemon(), setDaemon()

获取和设置线程是否为守护线程。

isInterrupted()

获取线程是否被中断。

 

start()

开始线程。

join()

等待指定线程中终止。

interrupt()

中断线程

 

静态方法

currentThread()

获取当前线程。

sleep()

使当前线程休眠指定的时间。

yield()

使当前线程暂停执行,让其它等待的线程执行。

interrupted()

获取当前线程是否被中断。

 

 

 

2. 通过Thread实现多线程

1. 通过继承Thread类并覆盖Threadrun()方法创建一个新的线程类。

2. 使用该线程类创建线程对象。

  1. public class ThreadTest
  2. {
  3.     public static void main(String[] args) throws Exception
  4.     {
  5.         TestThread th = new TestThread("thread 1");
  6.         th.start();
  7.         th.join();
  8.         System.out.println("'main' ended.");
  9.     }
  10.     
  11.     private static class TestThread extends Thread
  12.     {
  13.         public TestThread(String threadName)
  14.         {
  15.             super(threadName);
  16.         }
  17.         
  18.         @Override
  19.         public void run()
  20.         {
  21.             String thName = Thread.currentThread().getName();
  22.             System.out.printf("'%s' started. /n", thName);
  23.             for (int i = 0; i < 10; i++)
  24.             {
  25.                 System.out.println(i);
  26.             }
  27.             System.out.printf("'%s' ended. /n", thName);
  28.         }
  29.     }
  30. }

 

3. 通过Runnable实现多线程

1. 创建一个Runnable接口的实现类(实现run()方法)。

2. 通过Thread类包含Runnable的构造方法创建线程对象。

  Thread(Runnable target)

  Thread(ThreadGroup group, Runnable target)

  ThreadGroup group, Runnable target, String name)

  1. public class RunnableTest
  2. {
  3.     public static void main(String[] args) throws Exception
  4.     {
  5.         Thread th = new Thread(new TestRunnable(), "thread 1");
  6.         th.start();
  7.         th.join();
  8.         System.out.println("'main' ended.");
  9.     }
  10.     
  11.     private static class TestRunnable implements Runnable
  12.     {
  13.         @Override
  14.         public void run()
  15.         {
  16.             String thName = Thread.currentThread().getName();
  17.             System.out.printf("'%s' started. /n", thName);
  18.             for (int i = 0; i < 10; i++)
  19.             {
  20.                 System.out.println(i);
  21.             }
  22.             System.out.printf("'%s' ended. /n", thName);
  23.         }
  24.     }
  25. }

 

4. ThreadGroup

activeCount()

获取线程组中正在执行的线程数量。

activeGroupCount()

获取线程组中正在执行的线程组数量。

getMaxPriority(), setMaxPriority()

获取和设置最大优先级

getName()

获取线程组的名称。

getParent()

获取父线程组

interrupt()

中断线程组中的所有线程。

isDaemon(), setDaemon()

获取和设置线程组是否为守护线程。

parentOf(ThreadGroup)

判断线程组是否包含于指定线程组中。

 

 

5. 通过ThreadGroup管理线程

在创建线程对象时,通过包含ThreadGroup的构造方法创建,将线程加入指定线程组

  Thread(ThreadGroup group, Runnable target)

  Thread(ThreadGroup group, Runnable target, String name)

  Thread(ThreadGroup group, String name)

  1. public class ThreadGroupTest
  2. {
  3.     
  4.     public static void main(String[] args) throws Exception
  5.     {
  6.         // 创建线程组对象。
  7.         ThreadGroup tg = new ThreadGroup("group 1");
  8.         
  9.         // 向线程组中加入10个线程。
  10.         for (int i = 0; i < 10; i++)
  11.         {
  12.             Thread th = new Thread(tg, new TestRunnable(), "thread " + i);
  13.             th.start();
  14.         }
  15.         
  16.         // 等待2秒。
  17.         Thread.sleep(2000);
  18.         
  19.         // 中断所有线程。
  20.         tg.interrupt();
  21.         
  22.         // 输出
  23.         System.out.println(tg.activeCount());
  24.     }
  25.     
  26.     private static class TestRunnable implements Runnable
  27.     {
  28.         @Override
  29.         public void run()
  30.         {
  31.             String thName = Thread.currentThread().getName();
  32.             System.out.printf("'%s' started. /n", thName);
  33.             while (!Thread.currentThread().isInterrupted())
  34.             {
  35.             }
  36.             System.out.printf("'%s' ended. /n", thName);
  37.         }
  38.     }
  39. }

PART.2  通过Callable和FutureTask实现异步调用

 

1. Callable<V>

Ø  V为返回值的类型。

Ø  实现Callable接口需实现call方法。

Ø  Runnablerun方法相比,call方法具有返回值V和异常声明。

 

 

2. FutureTask<V>

V为返回值得类型。

cancel()

取消执行。

get()

阻塞获取执行结果。

get(long, TimeUnit)

指定阻塞的最长时间,获取执行结果。

isCancelled()

获取是否被取消。

isDone()

获取是否完成。

run()

开始执行。

 

 

3. 通过Callable和FutureTask异步执行

1. 创建一个Callable<V>的实现类。

2. 创建FutureTask<V>对象。

3. 执行创建的FutureTask对象。(run方法)

4. 通过FutureTask对象获取结果。(get方法)

  1. import java.util.concurrent.Callable;
  2. import java.util.concurrent.ExecutionException;
  3. import java.util.concurrent.FutureTask;
  4. public class FutureTaskTest
  5. {
  6.     public static void main(String[] args)
  7.     {
  8.         FutureTask<Integer> ct = null;
  9.         
  10.         ct = new FutureTask<Integer>(new TestCallable());
  11.         ct.run();
  12.         
  13.         try
  14.         {
  15.             int ret = ct.get();
  16.             System.out.println(ret);
  17.         }
  18.         catch (InterruptedException e)
  19.         {
  20.             // ct.get() 时线程被中断。 
  21.             e.printStackTrace();
  22.         }
  23.         catch (ExecutionException e)
  24.         {
  25.             // Callable在执行时出现异常。
  26.             e.printStackTrace();
  27.         }
  28.     }
  29.     private static class TestCallable implements Callable<Integer>
  30.     {
  31.         @Override
  32.         public Integer call() throws Exception
  33.         {
  34.             double i = Math.random() * 100;
  35.             return (int)i;
  36.         }
  37.     }
  38. }

4.处理FutureTask执行时发生的异常

  1. import java.util.concurrent.Callable;
  2. import java.util.concurrent.ExecutionException;
  3. import java.util.concurrent.FutureTask;
  4. public class FutureTaskExceptionTest
  5. {
  6.     public static void main(String[] args)
  7.     {
  8.         FutureTask<Integer> ct = null;
  9.         
  10.         ct = new FutureTask<Integer>(new TestCallable());
  11.         ct.run();
  12.         
  13.         try
  14.         {
  15.             int ret = ct.get();
  16.             System.out.println(ret);
  17.         }
  18.         catch (InterruptedException e)
  19.         {
  20.             // ct.get() 时线程被中断。 
  21.             e.printStackTrace();
  22.         }
  23.         catch (ExecutionException e)
  24.         {
  25.             // Callable在执行时出现异常。
  26.             System.out.println(e.getCause().getMessage());
  27.             System.out.println(e.getMessage());
  28.         }
  29.     }
  30.     private static class TestCallable implements Callable<Integer>
  31.     {
  32.         @Override
  33.         public Integer call() throws Exception
  34.         {
  35.             throw new Exception("An test exception.");
  36.         }
  37.     }
  38. }

PART.3  通过ExecutorService实现多线程

 

1. ExecutorService

awaitTermination

等待所有任务结束。

invokeAll

执行集合中的所有任务,返回所有Future。该方法将等待所有任务结束或指定的时间。

invokeAny

执行集合中的一个任务,返回该任务得返回值。

isShutdown

获取ExecutorService是否被shutdown

isTerminated

获取是否所有任务已经结束。

Shutdown

等待所有正在执行的任务结束。将没有执行的任务返回。不执行后新的任务。

shutdownNow

中断正在执行的任务。返回没有执行的任务。

submit

提交一个任务并开始执行。

 

2. 创建ExecutorService

Executors.newCachedThreadPool

Executors.newFixedThreadPool

Executors.newScheduledThreadPool

Executors.newSingleThreadExecutor

Executors.newSingleThreadScheduledExecutor

 

 

3. 通过ExecutorService实现多线程

1. 创建ExecutorService对象。

2. ExecutorServices对象提交任务。

3. 获得结果。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.Future;
  7. public class ExecutorServiceTest
  8. {
  9.     public static void main(String[] args) throws Exception
  10.     {
  11.         ExecutorService es = Executors.newCachedThreadPool();
  12.         
  13.         // 创建10个任务,将这些任务交由ExecutorService执行,保存这些任务的Future到List。
  14.         List<Future<Integer>> fs = new ArrayList<Future<Integer>>(10); 
  15.         for (int i = 0; i < 10; i++)
  16.         {
  17.             TestCallable t = new TestCallable();
  18.             Future<Integer> f = es.submit(t);
  19.             fs.add(f);
  20.         }
  21.         
  22.         // 等待执行结束。
  23.         Thread.sleep(1000);
  24.         
  25.         // 输出执行结果。
  26.         for (Future<Integer> f : fs)
  27.         {
  28.             System.out.println(f.get());
  29.         }
  30.         
  31.         // 关闭ExecutorService。
  32.         es.shutdown();
  33.     }
  34.     
  35.     private static class TestCallable implements Callable<Integer>
  36.     {
  37.         @Override
  38.         public Integer call() throws Exception
  39.         {
  40.             double ret = Math.random() * 100;
  41.             return (int)ret;
  42.         }
  43.     }
  44. }

4. 关闭ExecutorService

shutdown()                等待任务结束

shutdownNow()       中断任务

  1. import java.util.concurrent.Callable;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. public class ExecutorServiceShutdownTest
  5. {
  6.     public static void main(String[] args) throws Exception
  7.     {
  8.         // PART 1  测试shutdownNow()。
  9.         System.out.println("----- PART 1");
  10.         
  11.         // 创建ExecutorService。
  12.         ExecutorService es = Executors.newCachedThreadPool();
  13.         
  14.         // 开始10个任务。
  15.         System.out.println("----- Start all tasks...");
  16.         for (int i = 0; i < 10; i++)
  17.         {
  18.             TestCallable task = new TestCallable("task " + i);
  19.             es.submit(task);
  20.         }
  21.         
  22.         // 等待5秒。在此期间可能有任务结束。
  23.         System.out.println("----- Wait for 5 seconds.");
  24.         Thread.sleep(5000);
  25.         
  26.         // 结束所有任务。
  27.         System.out.println("----- Shutdown all tasks now.");
  28.         es.shutdownNow();
  29.         
  30.         System.out.println("----- End of PART 1");
  31.         Thread.sleep(1000);
  32.         
  33.         // 测试shutdown()。 
  34.         System.out.println("----- PART 2");
  35.         Thread.sleep(1000);
  36.         // 创建ExecutorService。
  37.         es = Executors.newCachedThreadPool();
  38.         
  39.         // 开始10个任务。
  40.         System.out.println("----- Start all tasks...");
  41.         for (int i = 0; i < 10; i++)
  42.         {
  43.             TestCallable task = new TestCallable("task " + i);
  44.             es.submit(task);
  45.         }
  46.         // 等待5秒。在此期间可能有任务结束。
  47.         System.out.println("----- Wait for 5 seconds.");
  48.         Thread.sleep(5000);
  49.         
  50.         // 结束所有任务。
  51.         System.out.println("----- Shutdown all tasks.");
  52.         es.shutdown();
  53.     
  54.         System.out.println("----- End of main.");
  55.     }
  56.     private static class TestCallable implements Callable<Void>
  57.     {
  58.         private String name;
  59.         
  60.         public TestCallable(String name)
  61.         {
  62.             this.name = name;
  63.         }
  64.         
  65.         @Override
  66.         public Void call() throws Exception
  67.         {
  68.             System.out.printf("'%s' started. /n", name);
  69.             
  70.             // 等待3 - 12秒。
  71.             try
  72.             {
  73.                 
  74.                 int w = (int)(Math.random() * 10 + 3);
  75.                 Thread.sleep(w*1000);
  76.             }
  77.             catch (InterruptedException e)
  78.             {
  79.                 System.out.printf("'%s' interrupted. /n", name);
  80.             }
  81.             
  82.             System.out.printf("'%s' ended. /n", name);
  83.             return null;
  84.         }
  85.     }
  86. }
Java线程同步 
   

PART.1  ReentrantLock

 

1. 通过ReentrantLocklockunlock方法获得和释放锁。

  1. import java.util.concurrent.locks.ReentrantLock;
  2. public class ReentrantLockTest
  3. {
  4.     private static ReentrantLock locker = new ReentrantLock();
  5.     
  6.     public static void main(String[] args) throws Exception
  7.     {
  8.         Thread th = new Thread(new TestRunnable());
  9.         
  10.         System.out.println("main: lock.");
  11.         locker.lock();
  12.         
  13.         System.out.println("main: starting Test.");
  14.         th.start();
  15.         
  16.         System.out.println("main: sleep for 3 seconds.");
  17.         Thread.sleep(3000);
  18.         
  19.         System.out.println("main: unlock.");
  20.         locker.unlock();
  21.     }
  22.     
  23.     private static class TestRunnable implements Runnable
  24.     {
  25.         @Override
  26.         public void run()
  27.         {
  28.             System.out.println("test: start and lock.");
  29.             locker.lock();
  30.             System.out.println("test: between lock and unlock.");
  31.             locker.unlock();
  32.             System.out.println("test: end.");
  33.         }
  34.     }
  35. }

22个线程分别向counter10,每次加1

  1. import java.util.concurrent.locks.ReentrantLock;
  2. public class ReentrantLockTest2
  3. {
  4.     private static ReentrantLock locker = new ReentrantLock();
  5.     private static int counter = 0;
  6.     
  7.     public static void main(String[] args) throws Exception
  8.     {
  9.         Thread th1 = new Thread(new TestRunnable());
  10.         Thread th2 = new Thread(new TestRunnable());
  11.         
  12.         th1.start();
  13.         th2.start();
  14.         
  15.         th1.join();
  16.         th2.join();
  17.         
  18.         System.out.println(counter);
  19.     }
  20.     
  21.     private static class TestRunnable implements Runnable
  22.     {
  23.         @Override
  24.         public void run()
  25.         {
  26.             for (int i = 0; i < 10; i++)
  27.             {
  28.                 locker.lock();
  29.                 try
  30.                 {
  31.                     int temp = counter + 1;
  32.                     Thread.sleep(100);
  33.                     counter = temp;
  34.                 }
  35.                 catch (InterruptedException e)
  36.                 {
  37.                     return;
  38.                 }
  39.                 finally
  40.                 {
  41.                     locker.unlock();
  42.                 }
  43.             }
  44.         }
  45.     }
  46. }

PART.2 Condition

 

1.       通过ReentrantLock创建Condition对象

2.       在获得锁的条件下,调用Conditionawait方法释放锁并等待其他线程调用同一Condition对象的signal方法。

3.       另一线程在获得锁的条件下调用Condition对象的signal方法。

  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. public class ConditionTest
  4. {
  5.     private static ReentrantLock locker = null;
  6.     private static Condition condition = null;
  7.     
  8.     public static void main(String[] args) throws Exception
  9.     {
  10.         locker = new ReentrantLock();
  11.         condition = locker.newCondition();
  12.         
  13.         Thread th = new Thread(new TestRunnable());
  14.         th.start();
  15.         
  16.         Thread.sleep(3000);
  17.         
  18.         System.out.println("main: signal all.");
  19.         // 调用condition.signalAll()将使Test线程中的阻塞结束。
  20.         locker.lock();
  21.         condition.signalAll();
  22.         locker.unlock();
  23.         
  24.         System.out.println("main: end.");
  25.     }
  26.     
  27.     private static class TestRunnable implements Runnable
  28.     {
  29.         @Override
  30.         public void run()
  31.         {
  32.             locker.lock();
  33.             try
  34.             {
  35.                 System.out.println("test: before 'condition.await()'");
  36.                 
  37.                 // await()将阻塞直到其他线程调用condition.signal。
  38.                 condition.await();
  39.                 
  40.                 System.out.println("test: after 'condition.await()'");
  41.                 Thread.sleep(1000);
  42.             }
  43.             catch (InterruptedException e)
  44.             {
  45.             }
  46.             finally 
  47.             {
  48.                 locker.unlock();
  49.             }
  50.         }
  51.     }
  52. }

生产者与消费者示例

 

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. public class ConditionTest2
  6. {
  7.     private static ReentrantLock locker;
  8.     private static Condition condition;
  9.     private static Queue<Integer> queue;
  10.     
  11.     public static void main(String[] args) throws Exception
  12.     {
  13.         locker = new ReentrantLock();
  14.         condition = locker.newCondition();
  15.         queue = new LinkedList<Integer>();
  16.         
  17.         Thread pth = new ProducerThread();
  18.         Thread cth = new ConsumerThread();
  19.         
  20.         pth.start();
  21.         cth.start();
  22.         
  23.         Thread.sleep(30 * 1000);
  24.         
  25.         pth.interrupt();
  26.         cth.interrupt();
  27.         
  28.         pth.join();
  29.         cth.join();
  30.     }
  31.     
  32.     
  33.     private static class ProducerThread extends Thread
  34.     {
  35.         @Override
  36.         public void run()
  37.         {
  38.             // 每0-500毫秒产生一个随机整数并加入队列。
  39.             while (!Thread.currentThread().isInterrupted())
  40.             {
  41.                 locker.lock();
  42.                 try
  43.                 {
  44.                     int x = (int)(Math.random() * 100);
  45.                     queue.offer(x);
  46.                     condition.signalAll();
  47.                     System.out.println("producer: " + x + ", signal all");
  48.                     // 随机休眠0-499毫秒
  49.                     Thread.sleep((int)(Math.random() * 500));
  50.                 }
  51.                 catch (InterruptedException e)
  52.                 {
  53.                     break;
  54.                 }
  55.                 finally 
  56.                 {
  57.                     locker.unlock();
  58.                 }
  59.             }
  60.             System.out.println("End of ProducerThread.");
  61.         }
  62.     }
  63.     
  64.     private static class ConsumerThread extends Thread
  65.     {
  66.         @Override
  67.         public void run()
  68.         {
  69.             // 每0-500毫秒从队列取出一个数并输出。
  70.             while (!Thread.currentThread().isInterrupted())
  71.             {
  72.                 locker.lock();
  73.                 try
  74.                 {
  75.                     // 如果队列为空,将等待ProducerThread向队列插入数据。
  76.                     while (queue.isEmpty())
  77.                     {
  78.                         System.out.println("consumer: Queue is empty.");
  79.                         condition.await();
  80.                     }
  81.                     int x  = queue.poll();
  82.                     System.out.println("consumer: " + x);
  83.                     
  84.                     // 随机休眠0-499毫秒
  85.                     Thread.sleep((int)(Math.random() * 500));
  86.                 }
  87.                 catch (InterruptedException e)
  88.                 {
  89.                     break;
  90.                 }
  91.                 finally
  92.                 {
  93.                     locker.unlock();
  94.                 }
  95.             }
  96.             System.out.println("End of ComsumerThread.");
  97.         }
  98.     }
  99. }

CyclicBarrier用于设置一个Barrier,达到Barrier的线程将等待,当所有线程都达到Barrier时,所有线程继续执行。

 

1.       创建CyclicBarrier时通过构造函数指定线程的数量n

2.       每个线程调用await方法等待其他线程。

3.       当有nawait方法被调用时,所有处于await的线程都将继续执行。

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierTest
  4. {
  5.     private static CyclicBarrier barrier = null;
  6.     
  7.     public static void main(String[] args)
  8.     {
  9.         // 初始化
  10.         barrier = new CyclicBarrier(10);
  11.         
  12.         // 启动10个线程
  13.         System.out.println("main: starting 10 threads.");
  14.         for (int i = 0; i < 10; i++)
  15.         {
  16.             Thread th = new Thread(new TestRunnable(), "thread " + i);
  17.             th.start();
  18.         }
  19.     }
  20.     
  21.     private static class TestRunnable implements Runnable
  22.     {
  23.         @Override
  24.         public void run()
  25.         {
  26.             String thName = Thread.currentThread().getName();
  27.             try
  28.             {
  29.                 // 随机等待5-14秒
  30.                 int n = (int)(Math.random() * 10 + 5);
  31.                 System.out.printf("%s: sleep for %d seconds. /n", thName, n);
  32.                 Thread.sleep(n * 1000);
  33.                 
  34.                 // 等待其他线程
  35.                 System.out.printf("%s: waiting for other threads. /n", thName);
  36.                 barrier.await();
  37.                 
  38.                 // 结束
  39.                 System.out.printf("%s: end. /n", thName);
  40.             }
  41.             catch (InterruptedException e)
  42.             {
  43.                 System.out.printf("%s: interrupted. /n", thName);
  44.                 return;
  45.             }
  46.             catch (BrokenBarrierException e)
  47.             {
  48.                 System.out.printf("%s: broken barrier. /n", thName);
  49.                 return;
  50.             }
  51.         }
  52.     }
  53. }

 

1.       在调用await方法时设置超时时间。

2.       当有一个await方法超时,所有处于await等待的线程将收到BrokenBarrierException,超时的线程自身将收到TimeoutException

3.       BrokenBarrier之后的所有await调用将直接抛出BrokenBarrierException

 

 

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. import java.util.concurrent.TimeUnit;
  4. import java.util.concurrent.TimeoutException;
  5. public class CyclicBarrierBrokenTest
  6. {
  7.     private static CyclicBarrier barrier = null;
  8.     
  9.     public static void main(String[] args)
  10.     {
  11.         // 初始化
  12.         barrier = new CyclicBarrier(10);
  13.         
  14.         // 启动10个线程
  15.         System.out.println("main: starting 10 threads.");
  16.         for (int i = 0; i < 10; i++)
  17.         {
  18.             Thread th = new Thread(new TestRunnable(), "thread " + i);
  19.             th.start();
  20.         }
  21.     }
  22.     
  23.     private static class TestRunnable implements Runnable
  24.     {
  25.         @Override
  26.         public void run()
  27.         {
  28.             String thName = Thread.currentThread().getName();
  29.             try
  30.             {
  31.                 // 随机等待5-14秒
  32.                 int n = (int)(Math.random() * 10 + 5);
  33.                 System.out.printf("%s: sleep for %d seconds. /n", thName, n);
  34.                 Thread.sleep(n * 1000);
  35.                 
  36.                 // 等待其他线程
  37.                 System.out.printf("%s: waiting for other threads. /n", thName);
  38.                 barrier.await(5, TimeUnit.SECONDS);
  39.                 
  40.                 // 结束
  41.                 System.out.printf("%s: end. /n", thName);
  42.             }
  43.             catch (InterruptedException e)
  44.             {
  45.                 System.out.printf("%s: interrupted. /n", thName);
  46.                 return;
  47.             }
  48.             catch (BrokenBarrierException e)
  49.             {
  50.                 System.out.printf("%s: broken barrier. /n", thName);
  51.                 return;
  52.             }
  53.             catch (TimeoutException e)
  54.             {
  55.                 System.out.printf("%s: timeout. /n", thName);
  56.                 return;
  57.             }
  58.         }
  59.     }
  60. }

当调用await线程达到CyclicBarrier的设置之后,CyclicBarrier将被重置,重新等待nawait调用。

 

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierResetTest
  4. {
  5.     private static CyclicBarrier barrier = null;
  6.     
  7.     public static void main(String[] args) throws Exception
  8.     {
  9.         barrier = new CyclicBarrier(2);
  10.         
  11.         Thread th1 = new Thread(new TestRunnable(), "thread 1");
  12.         Thread th2 = new Thread(new TestRunnable(), "thread 2");
  13.         
  14.         th1.start();
  15.         th2.start();
  16.         
  17.         Thread.sleep(60 * 1000);
  18.         
  19.         th1.interrupt();
  20.         th2.interrupt();
  21.         
  22.         th1.join();
  23.         th2.join();
  24.     }
  25.     
  26.     private static class TestRunnable implements Runnable
  27.     {
  28.         @Override
  29.         public void run()
  30.         {
  31.             String thName = Thread.currentThread().getName();
  32.             System.out.printf("%s: start. /n", thName);
  33.             
  34.             try
  35.             {
  36.                 while (true)
  37.                 {
  38.                     // 随机产生1-100的整数。
  39.                     int c = (int)(Math.random() * 100) + 1;
  40.                     
  41.                     // 随机等待0-4秒。
  42.                     int t = (int)(Math.random() * 5);
  43.                     System.out.printf("%s: sleep for %d seconds./n", thName, t);
  44.                     Thread.sleep(t * 1000);
  45.                     
  46.                     // 等待另1线程。
  47.                     barrier.await();
  48.                     
  49.                     // 输出产生的整数。
  50.                     System.out.printf("%s: %d /n", thName, c);
  51.                     
  52.                     // 等待其他线程输出。
  53.                     Thread.sleep(100);
  54.                 }
  55.             }
  56.             catch (InterruptedException e)
  57.             {
  58.                 System.out.printf("%s: interrupted. /n", thName);
  59.             }
  60.             catch (BrokenBarrierException e)
  61.             {
  62.                 e.printStackTrace();
  63.             }
  64.             
  65.             System.out.printf("%s: end. /n", thName);
  66.         }
  67.     }
  68. }

 

1.       在创建CyclicBarrier的时候指定通过Barrier时需要执行的语句。

2.       通过构造方法的Runnable参数指定。

3.       Runnable中的语句将由最后达到Barrier的线程执行。

 

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierActionTest
  4. {
  5.     private static CyclicBarrier barrier = null;
  6.     
  7.     public static void main(String[] args) throws Exception
  8.     {
  9.         barrier = new CyclicBarrier(10new BarrierAction());
  10.         
  11.         for (int i = 0; i < 10; i++)
  12.         {
  13.             Thread th = new Thread(new TestRunnable(), "thread " + i);
  14.             th.start();
  15.         }
  16.     }
  17.     
  18.     private static class TestRunnable implements Runnable
  19.     {
  20.         @Override
  21.         public void run()
  22.         {
  23.             try
  24.             {
  25.                 String thName = Thread.currentThread().getName();
  26.                 // System.out.printf("%s: start. /n", thName);
  27.                 
  28.                 // 随机等待0-9秒
  29.                 int t = (int)(Math.random() * 10);
  30.                 System.out.printf("%s: sleep for %d seconds. /n", thName, t);
  31.                 Thread.sleep(t * 1000);
  32.                 
  33.                 // 等待barrier
  34.                 barrier.await();
  35.                 System.out.printf("%s: end. /n", thName);
  36.             }
  37.             catch (InterruptedException e)
  38.             {
  39.                 e.printStackTrace();
  40.                 return;
  41.             }
  42.             catch (BrokenBarrierException e)
  43.             {
  44.                 e.printStackTrace();
  45.                 return;
  46.             }
  47.         }
  48.     }
  49.     
  50.     private static class BarrierAction implements Runnable
  51.     {
  52.         @Override
  53.         public void run()
  54.         {
  55.             String thName = Thread.currentThread().getName();
  56.             
  57.             System.out.printf("%s: barrier action. /n", thName);
  58.         }
  59.     }
  60. }

 

1. CountDownLatch

  1. CountDownLatch用于等待计数器计数。
  2. 在创建CountDownLatch时指定初始的整数。
  3. 调用CountDownLatch的await方法等待计数器到0。
  4. 每调用一次CountDownLatch的countDown方法,计数器减1。
  1. import java.util.concurrent.CountDownLatch;
  2. public class CountDownLatchTest
  3. {
  4.     private static CountDownLatch counter = null;
  5.     public static void main(String[] args) throws Exception
  6.     {
  7.         counter = new CountDownLatch(10);
  8.         Thread th1 = new Thread(new TestRunnable(), "thread 1");
  9.         Thread th2 = new Thread(new TestRunnable(), "thread 2");
  10.         th1.start();
  11.         th2.start();
  12.         counter.await();
  13.         System.out.println("main: after counter.await().");
  14.         th1.interrupt();
  15.         th2.interrupt();
  16.         th1.join();
  17.         th2.join();
  18.         System.out.println("main: end.");
  19.     }
  20.     private static class TestRunnable implements Runnable
  21.     {
  22.         @Override
  23.         public void run()
  24.         {
  25.             String thName = Thread.currentThread().getName();
  26.             System.out.printf("%s: start. /n", thName);
  27.             try
  28.             {
  29.                 while (true)
  30.                 {
  31.                     // 随机等待1-5秒
  32.                     int t = (int) (Math.random() * 5 + 1);
  33.                     System.out.printf("%s: sleep for %d seconds./n", thName, t);
  34.                     Thread.sleep(1000 * t);
  35.                     // 计数
  36.                     counter.countDown();
  37.                 }
  38.             }
  39.             catch (InterruptedException e)
  40.             {
  41.                 System.out.printf("%s: interrupted. /n", thName);
  42.             }
  43.             System.out.printf("%s: end. /n", thName);
  44.         }
  45.     }
  46. }

2. Exchanger

  1. Exchanger用于在2个线程中交换对象。
  2. an_object = exchanger.exchange(an_object)
  3. 例子中Producer向ArrayList中缓慢填充随机整数,Consumer从另一个ArrayList中缓慢取出整数并输出。
  4. 当Producer的ArrayList填满,并且Consumer的ArrayList为空时,2个线程交换ArrayList。 
  1. import java.util.ArrayList;
  2. import java.util.concurrent.Exchanger;
  3. public class ExchangerTest
  4. {
  5.     private static Exchanger<ArrayList<Integer>> exchanger = null;
  6.     private static ArrayList<Integer> buffer1 = null;
  7.     private static ArrayList<Integer> buffer2 = null;
  8.     public static void main(String[] args) throws Exception
  9.     {
  10.         exchanger = new Exchanger<ArrayList<Integer>>();
  11.         buffer1 = new ArrayList<Integer>(10);
  12.         buffer2 = new ArrayList<Integer>(10);
  13.         Thread pth = new ProducerThread();
  14.         Thread cth = new ConsumerThread();
  15.         pth.start();
  16.         cth.start();
  17.         Thread.sleep(60 * 1000);
  18.         System.out.println("main: interrupting threads.");
  19.         pth.interrupt();
  20.         cth.interrupt();
  21.         pth.join();
  22.         cth.join();
  23.         System.out.println("main: end.");
  24.     }
  25.     private static class ProducerThread extends Thread
  26.     {
  27.         @Override
  28.         public void run()
  29.         {
  30.             ArrayList<Integer> buff = buffer1;
  31.             try
  32.             {
  33.                 while (true)
  34.                 {
  35.                     if (buff.size() >= 10)
  36.                     {
  37.                         // 与consumer交换buffer.
  38.                         System.out.println("producer: exchanging.");
  39.                         buff = exchanger.exchange(buff);
  40.                         buff.clear();
  41.                     }
  42.                     // 随机产生一个0-100的整数。
  43.                     int x = (int) (Math.random() * 100);
  44.                     buff.add(x);
  45.                     System.out.println("producer: " + x);
  46.                     // 随机等待0-3秒 。
  47.                     int t = (int) (Math.random() * 3);
  48.                     Thread.sleep(t * 1000);
  49.                 }
  50.             }
  51.             catch (InterruptedException e)
  52.             {
  53.                 System.out.println("producer: interrupted.");
  54.             }
  55.         }
  56.     }
  57.     private static class ConsumerThread extends Thread
  58.     {
  59.         @Override
  60.         public void run()
  61.         {
  62.             ArrayList<Integer> buff = buffer2;
  63.             try
  64.             {
  65.                 while (true)
  66.                 {
  67.                     for (Integer x : buff)
  68.                     {
  69.                         System.out.println("consumer: " + x);
  70.                         // 随机等待0-3秒 。
  71.                         int t = (int) (Math.random() * 3);
  72.                         Thread.sleep(t * 1000);
  73.                     }
  74.                     // 与producer交换buffer。
  75.                     System.out.println("consumer: exchanging.");
  76.                     buff = exchanger.exchange(buff);
  77.                 }
  78.             }
  79.             catch (InterruptedException e)
  80.             {
  81.                 System.out.println("consumer: interrupted.");
  82.             }
  83.         }
  84.     }
  85. }

3. Semaphore

  1. Semaphore对象保存n个许可。(在构造方法指定)
  2. 一个线程可以从Semahpore中取出x个许可,当Semaphore对象中的许可数量不足x时将阻塞。
  3. 线程使用完许可后将许可归还给Semaphore。
  1. import java.util.ArrayList;
  2. import java.util.concurrent.Semaphore;
  3. public class SemaphoreTest
  4. {
  5.     private static Semaphore semaphore = null;
  6.     private static ArrayList<TestThread> threads = null;;
  7.     private static ThreadGroup group = null;
  8.     public static void main(String[] args) throws Exception
  9.     {
  10.         semaphore = new Semaphore(10);
  11.         threads = new ArrayList<TestThread>(5);
  12.         group = new ThreadGroup("no name");
  13.         for (int i = 0; i < 5; i++)
  14.         {
  15.             TestThread th = new TestThread("thread " + i, group);
  16.             threads.add(th);
  17.             th.start();
  18.         }
  19.         for (int i = 0; i < 60; i++)
  20.         {
  21.             System.out.println(i + " :/t" + getStatus());
  22.             Thread.sleep(1000);
  23.         }
  24.         group.interrupt();
  25.     }
  26.     private static String getStatus()
  27.     {
  28.         StringBuffer sb = new StringBuffer();
  29.         for (int i = 0; i < 5; i++)
  30.         {
  31.             sb.append(threads.get(i).getStatus());
  32.             sb.append("/t");
  33.         }
  34.         sb.append(":");
  35.         sb.append(10 - semaphore.availablePermits());
  36.         return sb.toString();
  37.     }
  38.     private static class TestThread extends Thread
  39.     {
  40.         private String status = "";
  41.         public String getStatus()
  42.         {
  43.             return status;
  44.         }
  45.         public TestThread(String name, ThreadGroup group)
  46.         {
  47.             super(group, name);
  48.         }
  49.         @Override
  50.         public void run()
  51.         {
  52.             String thName = Thread.currentThread().getName();
  53.             System.out.printf("%s: started. /n", thName);
  54.             try
  55.             {
  56.                 while (true)
  57.                 {
  58.                     int p = (int) (Math.random() * 4) + 1;
  59.                     status = "[" + p + "]";
  60.                     semaphore.acquire(p);
  61.                     status = " " + p + " ";
  62.                     Thread.sleep((long) (Math.random() * 3000) + 2000);
  63.                     semaphore.release(p);
  64.                 }
  65.             }
  66.             catch (InterruptedException e)
  67.             {
  68.                 System.out.printf("%s: interrupted. /n", thName);
  69.             }
  70.         }
  71.     }
  72. } 

Java 可中断线程

PART.1 无法中断的线程

一个无法中断的线程的例子。

  1. public class UninterruptableThread
  2. {
  3.     @SuppressWarnings("deprecation")
  4.     public static void main(String[] args) throws Exception
  5.     {
  6.         Thread th = new Thread(new TestRunnable());
  7.         
  8.         // 启动线程
  9.         System.out.println("main: start thread.");
  10.         th.start();
  11.         
  12.         // 等待2秒
  13.         Thread.sleep(2000);
  14.         
  15.         // 中断线程
  16.         System.out.println("main: interrupt thread.");
  17.         th.interrupt();
  18.         
  19.         // 等待2秒
  20.         Thread.sleep(2000);
  21.         
  22.         // 停止线程
  23.         System.out.println("main: stop thread.");
  24.         th.stop();
  25.     }
  26.     
  27.     private static class TestRunnable implements Runnable
  28.     {
  29.         @Override
  30.         public void run()
  31.         {
  32.             System.out.println("Thread started.");
  33.             while (true)
  34.             {
  35.                 // 避免由于while(true)导致编译失败。
  36.                 if (falsebreak;
  37.             }
  38.             
  39.             // 清理工作
  40.             System.out.println("Thread ended.");
  41.         }
  42.     }
  43. }
  • 输出结果:

main: start thread.
Thread started.
main: interrupt thread.
main: stop thread.

  • Thread对象的interrupt方法仅仅把该线程的一个标志置为true,该方法本身并不包含任何中断线程的操作。
  • stop方法可以将线程中止,但通过输出的结果可以发现,”Thread ended”并没有被输出,即线程本身不能进行任何清理工作。

PART.2 可中断的线程

  • 线程应不断检查isInterrupted是否为true,当其返回true时,应开始清理并结束线程。(Test1中的while循环)
  • Thread.sleep方法会在线程被中断时抛出InterruptedException,线程可以捕获该异常并开始清理和结束线程。(Test2中的Thread.sleep())
  • 如果循环中不时调用Thread.sleep,可以处理isInterrupted。

可中断线程的例子:

  1. public class GeneralTest
  2. {
  3.     public static void main(String[] args) throws Exception
  4.     {
  5.         Thread th1 = new Thread(new Test1());
  6.         Thread th2 = new Thread(new Test2());
  7.         
  8.         // 启动 Test1 和 Test2 线程。
  9.         System.out.println("main: starting 'Test1' and 'Test2'.");
  10.         th1.start();
  11.         th2.start();
  12.         
  13.         // 等待3秒。
  14.         System.out.println("main: sleeping for 3 seconds.");
  15.         Thread.sleep(3000);
  16.         
  17.         // 中断 Test1 和 Test2 线程。
  18.         System.out.println("main: interrupting 'Test1' and 'Test2'.");
  19.         th1.interrupt();
  20.         th2.interrupt();
  21.         
  22.         // 等待 Test1 和 Test2 线程结束。
  23.         System.out.println("main: waiting for 'Test1' and 'Test2' to end.");
  24.         th1.join();
  25.         th2.join();
  26.         
  27.         System.out.println("main: end.");
  28.     }
  29.     
  30.     private static class Test1 implements Runnable
  31.     {
  32.         @Override
  33.         public void run()
  34.         {
  35.             System.out.println("Test1: start.");
  36.             while (!Thread.currentThread().isInterrupted())
  37.             {
  38.                 // 其他操作...
  39.                 System.out.print("");
  40.             }
  41.             System.out.println("Test1: end.");
  42.         }
  43.     }
  44.     
  45.     private static class Test2 implements Runnable
  46.     {
  47.         @Override
  48.         public void run()
  49.         {
  50.             System.out.println("Test2: start.");
  51.             try
  52.             {
  53.                 while (true)
  54.                 {
  55.                     // 其他操作... 
  56.                     Thread.sleep(1000);
  57.                 }
  58.             }
  59.             catch (InterruptedException e)
  60.             {
  61.                 System.out.println("Test2: InterruptedException");
  62.             }
  63.             System.out.println("Test2: end.");
  64.         }
  65.     }
  66. }

PART.3 isInterrupted()和interrputed()方法的区别

  • isInterrupted方法是实例方法,interrupted方法是静态方法。

Thread.currentThread().isInterrupted()
Thread.interrupted()

  • interrupted方法在调用之后会将中断标志置为false。在只对线程调用一次interrupt的前提下interrupted方法只会返回一次true。
  • 使用interrupted方法判断应确保在判断之后开始结束线程。

isInterrupted和interrupted方法比较的例子:

  1. public class InterruptedStateTest
  2. {
  3.     public static void main(String[] args) throws Exception
  4.     {
  5.         // "Test1"
  6.         Thread th1 = new Thread(new Test1());
  7.         
  8.         // 启动 Test1 线程,并在3秒之后中断该线程。
  9.         th1.start();
  10.         Thread.yield();
  11.         
  12.         System.out.println("Test1 started... Waiting 3 seconds.");
  13.         Thread.sleep(3000);
  14.         
  15.         System.out.println("Interrupting Test1...");
  16.         th1.interrupt();
  17.         
  18.         Thread.sleep(1000);
  19.         
  20.         System.out.println("---------------------------------------");
  21.                 
  22.         // “Test2"
  23.         Thread th2 = new Thread(new Test2());
  24.         // 启动 Test2 线程,并在3秒之后中断该线程。
  25.         th2.start();
  26.         Thread.yield();
  27.         
  28.         System.out.println("Test2 started... Waiting 3 seconds.");
  29.         Thread.sleep(3000);
  30.         
  31.         System.out.println("Interrupting Test2...");
  32.         th2.interrupt();
  33.         
  34.         Thread.yield();
  35.         
  36.         // 主线程结束。
  37.         System.out.println("End of main.");
  38.     }
  39.     
  40.     private static class Test1 implements Runnable
  41.     {
  42.         @Override
  43.         public void run()
  44.         {
  45.             System.out.println("Test1 start...");
  46.             while (true)
  47.             {
  48.                 if (Thread.currentThread().isInterrupted())
  49.                 {
  50.                     if (Thread.currentThread().isInterrupted())
  51.                     {
  52.                         System.out.println("Interrupted...");
  53.                         break;
  54.                     }
  55.                 }
  56.             }
  57.             System.out.println("Test1 end...");
  58.         }
  59.     }
  60.     
  61.     private static class Test2 implements Runnable
  62.     {
  63.         @Override
  64.         public void run()
  65.         {
  66.             // 记录线程开始时间。
  67.             long startTime = System.currentTimeMillis();
  68.             
  69.             System.out.println("Test2 start... " +
  70. "Automatically ends in 6 sec.");
  71.             
  72.             while (true)
  73.             {
  74.                 // 连续判断2次Thread.interrupted()
  75.                 if (Thread.interrupted())
  76.                 {
  77.                     if (Thread.interrupted())
  78.                     {
  79.                         System.out.println("Interrupted...");
  80.                         break;
  81.                     }
  82.                 }
  83.                 
  84.                 // 如果线程2运行超过6秒将自动结束。
  85.                 if (System.currentTimeMillis() - startTime > 6000 )
  86.                 {
  87.                     System.out.println("5 seconds...");
  88.                     break;
  89.                 }
  90.             }
  91.             System.out.println("Test2 end");
  92.         }
  93.     }
  94. }

例子中Test1连续判断2次Thread.currentThread().isInterrupted(), Test1仍然可以正常中断。

  1. if (Thread.currentThread().isInterrupted())
  2. {
  3.     if (Thread.currentThread().isInterrupted())
  4.     {
  5.         // 结束线程。
  6.     }
  7. }

Test2连续判断2次Thread.interrupted(),因此Test2线程在被调用interrupt之后没有结束。

  1. if (Thread.interrupted())
  2. {
  3.     if (Thread.interrupted())
  4.     {
  5.     // 结束线程。
  6.     }
  7. }

PART.4 处理阻塞

阻塞操作如BufferedReader的readLine方法,ServerSocket的accept方法将导致线程不能判断isInterrupted(),因此线程中的阻塞不能永久阻塞。处理阻塞的方法有以下:

  • 在调用阻塞方法时设置超时时间:

方法

超时后的处理

ReentrantLock

ReadLock

WriteLock

tryLock(long, TimeUnit)

返回false

Condition

await(long, TimeUnit)

awaitNanos(long)

awaitUntil(Date)

返回false

Future

get(long, TimeUnit)

TimeoutException

CyclicBarrier

await(long, TimeUnit)

TimeoutException

CountDownLatch

await(long, TimeUnit)

返回false

Exchanger

exchange(V, long, TimeUnit)

TimeoutException

Semaphore

tryAcquire(long, TimeUnit)

返回false

BlockingQueue<E>

offer(E, long, TimeUnit)

poll(long, TimeUnit)

返回false

返回null

BlockingDeque<E>

offerFirst(E, long, TimeUnit)

offerLast(E, long, TimeUnit)

poolFirst(long, TimeUnit)

poolLast(long, TimeUnit)

返回false

 

返回null

ServerSocket

accept()

通过setSoTimeout设置超时时间。

SocketTimeoutException

  • 该方法在阻塞时如果线程被中断,可以抛出一个异常:

方法

异常

Thread

sleep(long)

join()

InterruptedException

 

ReentrantLock

ReadLock

WriteLock

lockInterruptibly()

InterruptedException

Condition

await()

InterruptedException

Future

get()

InterruptedException

CyclicBarrier

await()

InterruptedException

CountDownLatch

await()

InterruptedException

Exchanger

exchange(V)

InterruptedException

Semaphore

acquire()

InterruptedException

BlockingQueue<E>

put(E)

take()

InterruptedException

BlockingDeque<E>

putFirst(E)

putLast(E)

takeFirst(E)

takeLast(E)

InterruptedException

  • 调用不可中断阻塞方法的可中断版本:

阻塞方法

可中断方法

ReentrantLock

ReadLock

WriteLock

lock()

tryLock()

tryLock(long, TimeUnit)

lockInterruptibly()

Condition

awaitUninterruptibly()

await()

await(long, TimeUnit)

awaitNanos(long)

awaitUntil(Date)

Semaphore

acquireUninterruptibly()

acquire()

tryAcquire()

tryAcquire(long, TimeUnit)

  • 不能设置超时也不能抛出异常的阻塞方法:
  1. synchronized块,Object的wait方法。可以使用ReentrantLock和Condition替代。
  2. BufferedReader的readLine方法,ObjectInputStream得readObject方法。(如果底层流是通过Socket获得,可以通过Socket设置超时)

PART.5 处理Thread.sleep()

1. 捕获异常并结束线程

  • 捕获InterruptedException异常,开始清理操作并结束线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             // 需要进行的操作
  8.             Thread.sleep(500);
  9.         }
  10.     }
  11.     catch (InterruptedException e)
  12.     {
  13.     }
  14.     
  15.     // 清理操作
  16. }

2. 捕获异常,再次调用interrupt

  1. public void run()
  2. {
  3.     while (!Thread.currentThread().isInterrupted())
  4.     {
  5.         try
  6.         {
  7.             // 需要进行的操作 1
  8.             Thread.sleep(500);
  9.         }
  10.         catch (InterruptedException e)
  11.         {
  12.             // 再次调用interrupt
  13.             Thread.currentThread().interrupt();
  14.         }
  15.         
  16.         try
  17.         {
  18.             // 需要进行的操作 2
  19.             Thread.sleep(500);
  20.         }
  21.         catch (InterruptedException e)
  22.         {
  23.             // 再次调用interrupt
  24.             Thread.currentThread().interrupt();
  25.         }
  26.     }
  27.     
  28.     // 清理操作
  29. }

PART.6 处理ReentrantLock和Condition

1. 通过lockInterruptibly方法中断

  • 捕获lockInterruptibly方法可能跑出的InterruptedException,并结束线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             locker.lockInterruptibly();
  8.             // 其他操作
  9.             locker.unlock();
  10.         }
  11.     }
  12.     catch (InterruptedException e)
  13.     {
  14.     }
  15.     // 清理操作
  16. }

2. 通过不设置超时的tryLock方法中断

  • tryLock方法将不阻塞。
  • 通过捕获Thread.sleep的异常(或其他方法)中断线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             if (locker.tryLock())
  8.             {
  9.                 // 其他操作
  10.             }
  11.             
  12.             Thread.sleep(500);
  13.         }
  14.     }
  15.     catch (InterruptedException e)
  16.     {
  17.     }
  18. }

3. 通过设置超时的tryLock方法中断

  • 捕获tryLock方法在线程中断时抛出的InterrupedException并结束线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             if (locker.tryLock(1, TimeUnit.SECONDS))
  8.             {
  9.                 // 其他操作
  10.             }
  11.         }
  12.     }
  13.     catch (InterruptedException e)
  14.     {
  15.     }
  16.     // 清理操作
  17. }
4. 通过捕获Conditon的await方法抛出的异常中断
  • 捕获Condition的await方法抛出的异常并结束线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             locker.lockInterruptibly();
  8.             condition.await();
  9.             // 其他操作
  10.             locker.unlock();
  11.         }
  12.     }
  13.     catch (InterruptedException e)
  14.     {
  15.     }
  16.     // 清理操作
  17. }

5. 可中断的Producer和Consumer示例

  • produce方法在线程中断时将跑出InterruptedException。
  • run方法捕获该异常,并中断线程。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             produce();
  8.             Thread.sleep((int)(Math.random() * 3000));
  9.         }
  10.     }
  11.     catch (InterruptedException e)
  12.     {
  13.     }
  14.     System.out.println("producer: end.");
  15. }
  16. private void produce() throws InterruptedException
  17. {
  18.     locker.lockInterruptibly();
  19.     try
  20.     {
  21.         // Produce
  22.         int x = (int)(Math.random() * 100);
  23.         queue.offer(x);
  24.         emptyCondition.signalAll();
  25.         System.out.printf("producer: %d and signal all. queue = %d /n",
  26.                 x, queue.size());
  27.     }
  28.     finally
  29.     {
  30.         locker.unlock();
  31.     }
  32. }
  • Consumer线程被中断后不结束,直到队列内所有数据被输出。
  • 不使用Thread.currentThread().isInterrupted()而定义isInt记录中断,可以避免中断导致ReentrantLock方法的tryLock不能获得锁而直接抛出异常。
  1. public void run()
  2. {
  3.     // 线程是否被中断
  4.     boolean isInt = false;
  5.     
  6.     // 线程中断后,将队列内的数据全部读出,再结束线程。
  7.     while (!isInt || !queue.isEmpty())
  8.     {
  9.         try
  10.         {
  11.             consume();
  12.             Thread.sleep((int)(Math.random() * 3000));
  13.         }
  14.         catch (InterruptedException e)
  15.         {
  16.             isInt = true;
  17.         }
  18.     }
  19.     System.out.println("consumer: end.");
  20. }
  21. private void consume() throws InterruptedException
  22. {
  23.     if (!locker.tryLock(5, TimeUnit.SECONDS))
  24.     {
  25.         // 没有获得锁,不进行任何操作。 避免死锁。
  26.         return;
  27.     }
  28.     
  29.     try
  30.     {
  31.         // Consume
  32.         while (queue.isEmpty())
  33.         {
  34.             System.out.println("consumer: waiting for condition.");
  35.             if (!emptyCondition.await(5, TimeUnit.SECONDS))
  36.             {
  37.                 // 5秒没有等待到条件,不进行任何操作。
  38.                 // 避免中断后在此处等待。
  39.                 return;
  40.             }
  41.         }
  42.         int x = queue.poll();
  43.         System.out.printf("consumer: %d, queue=%d /n", x, queue.size());
  44.     }
  45.     finally
  46.     {
  47.         locker.unlock();
  48.     }
  49. }
PART.7 处理BlockingQueue
  • 使用BlockingQueue处理Consumer和Producer问题。
  • put和take方法可以在线程被中断时抛出InterruptedException。

Producer:

  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             int x = (int)(Math.random() * 100);
  8.             queue.put(x);
  9.             System.out.println("producer: " + x);
  10.             Thread.sleep((int)(Math.random() * 3000));
  11.         }
  12.     }
  13.     catch (InterruptedException e)
  14.     {
  15.     }
  16.     System.out.println("producer: end.");
  17. }

Consumer:

  1. public void run()
  2. {
  3.     try
  4.     {
  5.         while (true)
  6.         {
  7.             int x = queue.take();
  8.             System.out.println("consumer: " + x);
  9.             Thread.sleep((int)(Math.random() * 3000));
  10.         }
  11.     }
  12.     catch (InterruptedException e)
  13.     {
  14.     }
  15.     System.out.println("consumer: end.");
  16. }

PART.8 处理Socket和ServerSocket

1. 处理ServerSocket的accept方法

  • 调用ServerSocket的setSoTimeout方法设置超时时间。
  • 捕获并处理超时引起的SocketTimeoutException。
  • 不需要处理该异常。
  1. public void run()
  2. {
  3.     try
  4.     {
  5.         // 设置超时时间
  6.         serverSocket.setSoTimeout(2000);
  7.     }
  8.     catch (SocketException e)
  9.     {
  10.         e.printStackTrace();
  11.         System.exit(-1);
  12.     }
  13.     
  14.     while (!Thread.currentThread().isInterrupted())
  15.     {
  16.         try
  17.         {
  18.             @SuppressWarnings("unused")
  19.             Socket s = serverSocket.accept();
  20.         }
  21.         catch (SocketTimeoutException e)
  22.         {
  23.             // 超时,不进行任何处理,再次调用accept方法
  24.         }
  25.         catch (IOException e)
  26.         {
  27.             e.printStackTrace();
  28.         }
  29.     }
  30.     // 清理工作
  31. }

2. 处理包装自Socket的BufferedReader的readLine方法

  • 调用Socket的setSoTimeout方法设置超时时间。
  • BufferedReader的readLine方法在阻塞指定的时间后将抛出SocketTimeoutException。
  • 不需要处理该异常。
  1. public void run()
  2. {
  3.     BufferedReader reader = null;
  4.     
  5.     try
  6.     {
  7.         // 建立测试用的链接
  8.         serverSocket = new ServerSocket(10009);
  9.         socket = new Socket("127.0.0.1"10009);
  10.         
  11.         Thread.sleep(500);
  12.         Socket s = serverSocket.accept();
  13.         
  14.         // 向socket发送5行数据
  15.         OutputStreamWriter w = new OutputStreamWriter(
  16.                 s.getOutputStream());
  17.         w.write("line1 /n line2 /n line3 /n line4 /n line5 /n");
  18.         w.flush();
  19.         
  20.         // 设置超时
  21.         socket.setSoTimeout(1000);
  22.         // 创建BufferedReader
  23.         reader = new BufferedReader(
  24.                 new InputStreamReader(socket.getInputStream()));
  25.     }
  26.     catch (IOException e)
  27.     {
  28.         e.printStackTrace();
  29.         System.exit(-1);
  30.     }
  31.     catch (InterruptedException e)
  32.     {
  33.         e.printStackTrace();
  34.         System.exit(-1);
  35.     }
  36.     
  37.     while (!Thread.currentThread().isInterrupted())
  38.     {
  39.         try
  40.         {
  41.             String s = reader.readLine();
  42.             
  43.             if (s == null)
  44.             {
  45.                 // 流结束
  46.                 break;
  47.             }
  48.             
  49.             // 输出读取的数据
  50.             System.out.println("thread: " + s);
  51.         }
  52.         catch (SocketTimeoutException e)
  53.         {
  54.             System.out.println("thread: socket timeout.");
  55.         }
  56.         catch (IOException e)
  57.         {
  58.             e.printStackTrace();
  59.         }
  60.     }
  61.     
  62.     // 清理
  63.     try { serverSocket.close(); } catch (Exception e) { }
  64.     try { socket.close(); } catch (Exception e) { }
  65.     System.out.println("thread: end.");
  66. }

3. 处理包装自Socket的ObjectInputStream的readObject方法

  • 与readLine的处理方法类似。
  • 调用Socket的setSoTimeout方法设置超时时间。
  • ObjectInputStream的readObject方法在阻塞指定的时间后将抛出异常。
  • 不需要处理该异常。
  1. public void run()
  2. {
  3.     ObjectInputStream ois = null;
  4.     try
  5.     {
  6.         // 建立测试用的链接
  7.         serverSocket = new ServerSocket(10009);
  8.         socket = new Socket("127.0.0.1"10009);
  9.         Thread.sleep(500);
  10.         Socket s = serverSocket.accept();
  11.         // 向socket发送3个对象
  12.         ObjectOutputStream oos = new ObjectOutputStream(
  13.                 s.getOutputStream());
  14.         oos.writeObject(new TestData("object 1"));
  15.         oos.writeObject(new TestData("object 2"));
  16.         oos.writeObject(new TestData("object 3"));
  17.         // 设置超时
  18.         socket.setSoTimeout(1000);
  19.         // 创建ObjectInputStream
  20.         ois = new ObjectInputStream(socket.getInputStream());
  21.     }
  22.     catch (IOException e)
  23.     {
  24.         e.printStackTrace();
  25.         System.exit(-1);
  26.     }
  27.     catch (InterruptedException e)
  28.     {
  29.         e.printStackTrace();
  30.         System.exit(-1);
  31.     }
  32.     while (!Thread.currentThread().isInterrupted())
  33.     {
  34.         try
  35.         {
  36.             TestData s = (TestData)ois.readObject();
  37.             if (s == null)
  38.             {
  39.                 // 流结束
  40.                 break;
  41.             }
  42.             // 输出读取的数据
  43.             System.out.println("thread: " + s.data);
  44.         }
  45.         catch (SocketTimeoutException e)
  46.         {
  47.             System.out.println("thread: socket timeout.");
  48.         }
  49.         catch (IOException e)
  50.         {
  51.             e.printStackTrace();
  52.         }
  53.         catch (ClassNotFoundException e)
  54.         {
  55.             e.printStackTrace();
  56.         }
  57.     }
  58.     // 清理
  59.     try { serverSocket.close(); } catch (Exception e) { }
  60.     try { socket.close(); } catch (Exception e) { }
  61.     System.out.println("thread: end.");
  62. }

其中,TestData是一个简单的可序列化的类。

  1. private static class TestData implements Serializable
  2. {
  3.     private static final long serialVersionUID = 6147773210845607198L;
  4.     public String data;
  5.     public TestData(String data)
  6.     {
  7.         this.data = data;
  8.     }
  9. }

 

PART.9 总结

见“PART.2可中断的线程”和“PART.4 处理阻塞”。

 


原创粉丝点击