并发(一)

这个月,总结一下thread的相关知识,把基础知识弄得更牢固一下,学习先增加深度在扩展广度。

声明:文章内容以及部分代码示例,参考了《Thinking in Java》(Java编程思想)这本书。

该书绝对是java从业人员的宝典之一。强烈推荐。

 

1 并发

并发通常是提高运行在单处理器上的程序的性能。

一般它或提高程序执行效率,或为设计某些类型的程序提供更易用的模块,或两者都有。

 在这里说一下线程安全的概念,多线程访问同一代码,不会产生不确定的结果,这样的话我们就说线程是安全的。

 

2 基本线程机制

2.1 定义任务,创建线程

一般是两种方式,一是继承一个thread类,另一种是实现Runnable接口。

下面给出代码示例:

 1 public class LiftOff implements Runnable{
 2 
 3     protected int countDown = 10;
 4     private static int taskCount = 0;
 5     // 标识符id可以用来区分任务的多个实例,它是final的,
 6     // 因为它一旦被初始化之后就不希望被修改
 7     private final int id = taskCount++;
 8     public LiftOff() {}
 9     public LiftOff(int countDown) {
10         
11     }
12     public String status() {
13         return "#" + id + "(" + 
14     (countDown > 0 ? countDown : "LiftOff") + ").";
15     }
16     public void run() {
17         
18         while(countDown-- > 0){
19             System.out.println(status());
20             Thread.yield();
21         }
22     }
23 }
View Code
1 public class ThreadDemo01 extends Thread{
2     public static void main(String args[]){
3         LiftOff lift = new LiftOff();
4         lift.run();
5     }
6 }
View Code
1 public class ThreadDemo02 extends Thread{
2     public static void main(String args[]){
3         Thread thread = new Thread(new LiftOff());
4         thread.start();
5     }
6 
7 }
View Code

执行结果如下:

#0(9).
#0(8).
#0(7).
#0(6).
#0(5).
#0(4).
#0(3).
#0(2).
#0(1).
#0(LiftOff).
View Code

大家查看API会发现,Thread类继承了Runnable接口,所以,线程最终是通过Runnable接口来实现的。推荐使用Runnable接口的方式,因为这样它还可以继承其它的类,增加自身的灵活性。

下面给出一个驱动多线程的示例:

 1 public class ThreadDemo03 {
 2 
 3     public static void main(String[] args) {
 4 
 5         for (int i = 0; i < 5; i++) {
 6             new Thread(new LiftOff()).start();
 7         }
 8     }
 9 
10 }
View Code

 

2.2 使用Executor

书中写明,在JAVA 6中,Executor是启动任务的优选方法,但是目前在JAVA 8中,是不是优选,我不知道。

Executor相当于客户端和线程之间的一个桥梁,由它执行任务。

常用的Executor有newCachedThreadPool(首选), FixedThreadPool(需指定线程数量), SingleThreadExcutor等。

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 
 4 public class ThreadDemo04 {
 5     public static void main(String[] args) {
 6 
 7         ExecutorService service = Executors.newCachedThreadPool();
 8         
 9         // ExecutorService service = Executors.newFixedThreadPool(2);
10         // ExecutorService service = Executors.newSingleThreadExecutor();
11         
12         for (int i = 0; i < 5; i++) {
13             service.execute(new LiftOff());
14         }
15         // shutDown方法,拒绝接受新的任务。我认为类似于io的close
16         service.shutdown();
17         System.out.println("------------");
18     }
19 }
View Code

 

2.3 从任务中产生返回值

Runnable只能执行任务,不能返回结果和异常。为了返回结果,可以实现Callable接口。

代码示例如:

 1 import java.util.LinkedList;
 2 import java.util.List;
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.ExecutorService;
 6 import java.util.concurrent.Executors;
 7 import java.util.concurrent.Future;
 8 
 9 public class ThreadDemo06 {
10 
11     public static void main(String[] args) {
12 
13         ExecutorService service = Executors.newCachedThreadPool();
14         List<Future<String>> list = new LinkedList<Future<String>>();
15         for (int i=0 ; i< 10 ; i++){
16             list.add(service.submit(new TaskWithResult(i)));
17         }
18         for (Future<String> fs : list) {
19             try {
20                 // get方法会或许返回值,如果任务尚未执行结束,会一直等待,造成阻塞
21                 // 可以用isDone方法来判断,任务是否执行结束
22                 System.out.println("future done? " + fs.isDone());
23                 System.out.println(fs.get());
24             } catch (InterruptedException | ExecutionException e) {
25                 e.printStackTrace();
26                 return;
27             } finally {
28                 service.shutdown();
29             }
30         } 
31     }
32 }
33 
34 class TaskWithResult implements Callable<String> {
35 
36     private int id;
37     public TaskWithResult (int id) {
38         this.id = id;
39     }
40     @Override
41     public String call() throws Exception {
42         return "result of TaskWithResult " + id;
43     }
44 }
View Code

执行结果:

future done? true
result of TaskWithResult 0
future done? true
result of TaskWithResult 1
future done? true
result of TaskWithResult 2
future done? true
result of TaskWithResult 3
future done? true
result of TaskWithResult 4
future done? true
result of TaskWithResult 5
future done? true
result of TaskWithResult 6
future done? true
result of TaskWithResult 7
future done? true
result of TaskWithResult 8
future done? true
result of TaskWithResult 9
View Code

 

2.4 后台线程

所谓后台线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的后台线程结束时,程序也就终止了,同时杀死进程中的所有后台线程。(摘自《Java编程思想》第21章)

代码示例如下:

 1 import java.util.concurrent.TimeUnit;
 2 
 3 public class SimpleDaemons implements Runnable {
 4 
 5     @Override
 6     public void run() {
 7 
 8         while (true) {
 9             try {
10                 TimeUnit.MICROSECONDS.sleep(100);
11                 System.out.println(Thread.currentThread() + " " + this);
12             } catch (InterruptedException e) {
13                 e.printStackTrace();
14                 System.out.println("sleep() intertupted");
15             }
16         }
17     }
18     
19     public static void main(String[] args) throws InterruptedException {
20         for (int i = 0; i < 10; i++) {
21 
22             Thread daemon = new Thread(new SimpleDaemons());
23             daemon.setDaemon(true);
24             daemon.start();
25         }
26         System.out.println("All daemons started");
27         TimeUnit.MICROSECONDS.sleep(175);
28     }
29 }
View Code

 

posted @ 2017-09-18 09:22  Mr.袋鼠  阅读(172)  评论(0编辑  收藏  举报