线程的使用经验(包括 Thread/Executor/Lock-free/阻塞/并发/锁等)

本次内容列表:

1.使用线程的经验:设置名称、响应中断、使用ThreadLocal

2.Executor:ExecutorService和Future

3.阻塞队列:put和take、offer和poll、drainTo

4.线程间的协调手段:lock、condition、wait、notify、notifyAll

5.Lock-free:atomic、concurrentMap.putlfAbsent、CopyOnWriteArrayList

6.关于锁使用的经验介绍

7.并发流程控制手段:CountDownlatch、Barrier

8.定时器:ScheduledExecutorService、大规模定时器TimeWheel

9.并发三大定律:Amdahl、Gustafson、Sun-Ni

1.线程的经验:无论何种方式,启动一个线程,就要给它一个名字。这对排错诊断系统监控有帮助。否则诊断问题时,无法直观知道某个线程的用途

设置名称:以下为常用的几种命名方式:

1     //命名方式一:
2     Thread thread = new Thread("thread name one") {
3         public void run() {
4             //do xxx
5         }
6     };
1     //命名方式二:
2     Thread thread = new Thread() {
3         public void run() {
4             //do xxx
5         }
6     };
7     thread.setName("thread name two");
8     thread.start();
 1 //命名方式三:
 2 public class MyThread extends Thread{
 4     public MyThread() {
 5         super("thread name three");
 6     }
 7     public void run() {
 8         //do xxx
 9     }
10 }
11 MyThread thread = new MyThread();
12 thread.start();  
1 //命名方式四:
2 Thread thread = new Thread(task, "thread name four");
3 thread.start();

响应线程中断:thread.interrupt(); 程序应该对线程中断作出恰当的响应

 1      //中断响应方式一:
 2     Thread thread = new Thread("interrupt test") {
 3         public void run() {
 4             for(;;) {
 5                 try {
 6                     doXXX();
 7                 } catch(InterruptedException e) {
 8                     break;
 9                 } catch(Exception e) {
10                     //handle Exception
11                 }
12             }
13         }
14     };
15     thread.start();
 1     //中断响应方式二:    
 2     Thread thread = new Thread("interrupt test") {
 3         public void run() {
 4             for(;;) {
 5                 if(Thread.interrupted()) {
 6                     break;
 7                 }
 8             }
 9         }
10     };
11     thread.start();
1     //中断响应方式三:    
2     public void foo() throws InterruptedException{
3         if(Thread.interrupted()) {
4             throw new InterruptedException();
5         }
6     }

ThreadLocal(局部线程变量):它的功能非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。使用ThreadLocal,一般都是声明在静态变量中,如果不断的创建ThreadLocal而且没有调用其remove方法,将会导致内存泄漏。如果是static的ThreadLocal,一般不需要调用remove。

 2.Executor

  为了方便并发执行任务,使用Executor用来专门执行任务的实现,任务的提交者不需要在创建管理线程,使用更方便,也减少了开销。

   java.util.concurrent.Executors是Executor的工厂类,通过Executors可以创建你所需要的Executor。

 任务的提交者和执行者之间的通讯手段

 1     ExecutorService executor = Executors.newSingleThreadExecutor();
 2     Callable<Object> task = new Callable<Object>() {
 3         @Override
 4         public Object call() throws Exception {
 5             Object result = "";
 6             return result;
 7         }
 8     };
 9     public void subTask() {
10         Future<Object> future = executor.submit(task);
11         try {
12             future.get();    //等待至完成
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         } catch (ExecutionException e) {
16             e.printStackTrace();
17         }
18     }

Task Submitter

1     Future<Object> future = executor.submit(task);
2     //等待到任务被执行完毕返回结果
3     //如果任务执行出错,这里会抛ExecutionException
4     future.get();
5     //等待3秒,超时后会抛TimeoutException
6     future.get(3, TimeUnit.SECONDS);

Task Executor

1     Callable<Object> task = new Callable<Object>() {
2         @Override
3         public Object call() throws Exception {
4             Object result = ...;
5             return result;
6         }
7     };

Task Submitter 把任务提交给Executor执行,他们之间需要一种通讯手段,这种手段的具体实现,通常叫做Future。Future通常包括get(阻塞至任务完成),cancel, get(timeout)(等待一段时间)等等。Future也用于异步变同步的场景。

3.阻塞队列:阻塞队列,是一种常用的并发数据结构,常用域生产者-消费者模式。

  有多种阻塞队列:

  ArrayBlockingQueue(最常用)

  LinkedBolckingQueue(不会满的)

  SynchronousQueue(size为0)

  PriorityBlockingQueue

阻塞中常用的方法有:

注:在使用BlockingQueue的时候,尽量不要使用从Queue继承下来的方法,否则就失去了Blocking的特性了。

例1:

 1         final BlockingQueue<Object> blockingQ = new ArrayBlockingQueue<Object>(10);
 2         Thread thread = new Thread("consumer thread") {
 3             public void run() {
 4                 for(;;) {
 5                     try {
 6                         Object object = blockingQ.take();    //等到有数据才继续
 7                         handle(object);    //处理
 8                     } catch (InterruptedException e) {
 9                         break;
10                     } catch(Exception e) {
11                         e.printStackTrace();
12                     }   
13                 }
14             }
15         };    

例2:

 1 final BlockingQueue<Object> blockingQ = new ArrayBlockingQueue<Object>(10);
 2     Thread thread = new Thread("consumer thread two") {
 3         public void run() {
 4             for(;;) {
 5                 try {
 6                     Object object = blockingQ.poll(1, TimeUnit.SECONDS);    //防止死锁
 7                     if(object == null) {
 8                         //TODO
 9                         continue;    //或者进行其他操作
10                     }
11                 } catch (InterruptedException e) {
12                     break;
13                 } catch (Exception e) {
14                     e.printStackTrace();
15                 }
16             }
17         }
18     };
原文地址:https://www.cnblogs.com/sun-flower1314/p/9726852.html