多线程学习

1.什么是多线程?主要理解进程和线程。
  进程:操作系统管理的基本运行单元,只是一个静态的概念,本身不能被执行。一个.exe文件,一个class文件就是一个进程,平时我们所说的一个进程开始执行了,其实是主线程被执行了。
  多线程:就是一个进程里不同的执行路径。其实CPU一次只能执行同一个线程,由于不同线程之间切换的时间差很小,给人的感觉是同时进行而已。(个人理解为将CPU的利用率最大化)
 
2.如何创建线程?
  实现runnable接口
  继承Thread类(Thread类其实也是实现了runnable接口的子类)。
  常见的创建线程的方式:
  Thread thread = new Thread(
    public void run(){
      //实现的业务逻辑
    }
  ).start();
 
3.线程的生命周期:
  创建一个线程-》runnable状态等待被调用-》running状态-》dead(执行完或者抛出异常)
          阻塞状态在runnable 和 running 之间
  注意:如果直接调用线程的run方法即thread.run();那么是方法调用,不会呈多线程效果。
 
4.线程控制的基本方法
  1.isAlive()判断线程是否终止
  2.getPriority()/setPriority()获取/设置优先级
  3.Thread.sleep()当前线程睡眠,可指定毫秒数
  4.join()等待线程结束,在恢复此线程继续执行
  5.yield() 让出CPU,进入runnable等待被调度
  6.wait()当前线程进入对象的waitpool
  7.notify()/notifyAll()唤醒一个或者唤醒对象所有的waitPoll
 
5.sleep()方法和wait()方法的区别 ?
  1.sleep方法是Thread类的,而wait方法是Object类的
  2.调用sleep方法不会释放对象锁,调用wait方法会释放对象锁
 
6.不要通过thread.stop()的方式终止线程,此方法为强制关闭线程,有些资源不会被释放。
 
7.关键字synchronized
 
  同步代码块synchronized(this){
    ......
  }
 
  synchronized method(){.......} 二者都是在执行的过程中都是锁定当前对象,是多线程学习的重点。
  此处有个细节:同步方法时虽然锁住的是对象,但是没有加锁的方法依然可以异步访问。
8.线程死锁:程序中过多的同步会产生死锁。代码演示:
  
 1 /**
 2  * 代码演示线程死锁 一个简单的死锁类
 3  * 
 4  * 当DeadLock类的对象flag==1时(lock1),先锁定o1,睡眠500毫秒
 5  * 
 6  * 而lock1在睡眠的时候另一个flag==0的对象(lock2)线程启动,先锁定o2,睡眠500毫秒
 7  * 
 8  * lock1睡眠结束后需要锁定o2才能继续执行,而此时o2已被lock2锁定;
 9  * 
10  * lock2睡眠结束后需要锁定o1才能继续执行,而此时o1已被lock1锁定;
11  * 
12  * lock1、lock2相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。
13  */
14 
15 public class TestDeadLock implements Runnable {
16     public int flag = 1;
17     static Object o1 = new Object(), o2 = new Object();
18 
19     @Override
20     public void run() {
21         System.out.println("flag=" + flag);
22         if (flag == 1) {
23             synchronized (o1) {
24                 try {
25                     Thread.sleep(1000);
26                 } catch (InterruptedException e) {
27                     // TODO Auto-generated catch block
28                     e.printStackTrace();
29                 }
30                 synchronized (o2) {
31                     System.out.println("1");
32                 }
33             }
34         }
35         if (flag == 0) {
36             synchronized (o2) {
37                 try {
38                     Thread.sleep(500);
39                 } catch (InterruptedException e) {
40                     // TODO Auto-generated catch block
41                     e.printStackTrace();
42                 }
43                 synchronized (o1) {
44                     System.out.println("0");
45                 }
46             }
47         }
48     }
49 
50     public static void main(String[] args) throws InterruptedException {
51         TestDeadLock lock1 = new TestDeadLock();
52         TestDeadLock lock2 = new TestDeadLock();
53 
54         lock1.flag = 1;
55         lock2.flag = 0;
56 
57         new Thread(lock1).start();
58         new Thread(lock2).start();
59     }
60 
61 }
View Code

9.与多线程相关的几个API

  threadLocal :是每个线程独立拥有的对象,在当前线程中数据共享。set() 、get()方法====Map<Thread,变量>

  timer: 定时器 请见timertest。new Timer().schedule(new TimerTask(){});创建一个定时器->计划什么时候执行->创建一个任务放到计划里

  CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。await()->countDown()->当计数器为0时,程序才继续向下执行(很有用。)

 1 package tcl.o2o.it.threadinjdk5;
 2 
 3 import java.util.concurrent.CountDownLatch;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 
 7 public class Learn03CountdownLatchTest {
 8 
 9     public static void main(String[] args) {
10         ExecutorService service = Executors.newCachedThreadPool(); // 创建一个线程池
11         final CountDownLatch cdOrder = new CountDownLatch(1);// 指挥官的命令,设置为1,指挥官一下达命令,则cutDown,变为0,战士们执行任务
12         final CountDownLatch cdAnswer = new CountDownLatch(3);// 因为有三个战士,所以初始值为3,每一个战士执行任务完毕则cutDown一次,当三个都执行完毕,变为0,则指挥官停止等待。
13         for (int i = 0; i < 3; i++) {
14             Runnable runnable = new Runnable() {
15                 public void run() {
16                     try {
17                         System.out.println("线程" + Thread.currentThread().getName() + "正准备接受命令");
18                         cdOrder.await(); // 战士们都处于等待命令状态
19                         System.out.println("线程" + Thread.currentThread().getName() + "已接受命令");
20                         Thread.sleep((long) (Math.random() * 10000));
21                         System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果");
22                         cdAnswer.countDown(); // 任务执行完毕,返回给指挥官,cdAnswer减1。
23                     } catch (Exception e) {
24                         e.printStackTrace();    
25                     }
26                 }
27             };
28             service.execute(runnable);// 为线程池添加任务
29         }
30         try {
31             Thread.sleep((long) (Math.random() * 10000));
32 
33             System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令");
34             cdOrder.countDown(); // 发送命令,cdOrder减1,处于等待的战士们停止等待转去执行任务。
35             System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果");
36             cdAnswer.await(); // 命令发送后指挥官处于等待状态,一旦cdAnswer为0时停止等待继续往下执行
37             System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果");
38         } catch (Exception e) {
39             e.printStackTrace();
40         }
41         service.shutdown(); // 任务结束,停止线程池的所有线程
42 
43     }
44 }
View Code

10.Lock 和 Condition

  jdk1.5新特性锁:
    ReentrantLock通用锁和ReentrantReadWriteLock读写锁。
    ReentrantLock和synchronized方法类似 只不过是通过lock()和unlock()控制边界。
  重点读写锁:除了read和read之外的任和锁都互斥
 
11.condition:Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
 
12.线程池的使用
  由于线程的生命周期中包括创建、就绪、运行、阻塞、销毁阶段,当我们待处理的任务数目较小时,我们可以自己创建几个线程来处理相应的任务,但当有大量的任务时,由于创建、销毁线程需要很大的开销,运用线程池这些问题就大大的缓解了。
  Executors.newFixedThreadPool(3)// 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  Executors.newCachedThreadPool()//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  Executors.newSingleThreadExecutor()//创建一个单线程化的线程池,它只会用唯一的工作线程来执行任、务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
  corePoolSize、maximumPoolSize、largestPoolSize
 
13.jdk1.5新特性Callable和Future(Future用于接收实现了Callable接口的线程执行结果)
  定义:callable接口类似于runnable,但是runnable不会有返回结果,callable有返回结果可以被future拿到
  ExecutorService 的submit 和 excute的区别 ,前者有返回值future,execute没有返回值
 
  CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(es); 批量提交任务,并获取返回结果
  
 1 package tcl.o2o.it.threadinjdk5;
 2 
 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 Learn06ThreadFutureAndCallable01 {
10 
11     public static void main(String[] args) throws InterruptedException, ExecutionException {
12         // TODO Auto-generated method stub
13         ExecutorService es = Executors.newSingleThreadExecutor();
14         Future<String> future = es.submit(new Callable<String>() {
15             @Override
16             public String call() throws Exception {
17                 // TODO Auto-generated method stub
18                 System.out.println("线程开始执行");
19                 Thread.sleep(1000);
20                 return "hello world";
21             }
22         });
23         
24         es.shutdown();
25         System.out.println("等待返回结果");
26         System.out.println(future.get());
27     }
28 
29 }
View Code

14.Semaphore-信号灯机制 当我们创建一个可扩展大小的线程池,并且需要在线程池内同时让有限数目的线程并发运行时,就需要用到Semaphore(信号灯机制)。acquire和release方法。

 1 public class Learn08SemaphoreTest {
 2     public static void main(String[] args) {
 3         ExecutorService service = Executors.newCachedThreadPool();
 4         final Semaphore sp = new Semaphore(3);
 5         for (int i = 0; i < 5; i++) {
 6             Runnable runnable = new Runnable() {
 7                 public void run() {
 8                     try {
 9                         sp.acquire();
10                     } catch (InterruptedException e1) {
11                         e1.printStackTrace();
12                     }
13                     System.out.println("线程" + Thread.currentThread().getName() + "进入,当前已有"
14                             + (3 - sp.availablePermits()) + "个并发");
15                     try {
16                         Thread.sleep((long) (Math.random() * 10000));  
17                     } catch (InterruptedException e) {
18                         e.printStackTrace();
19                     }
20                     System.out.println("线程" + Thread.currentThread().getName() + "即将离开");
21                     sp.release();
22                     // 下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
23                     System.out.println("线程" + Thread.currentThread().getName() + "已离开,当前已有"
24                             + (3 - sp.availablePermits()) + "个并发");
25                 }
26             };
27             service.execute(runnable);
28         }
29     }
30 }
View Code

 

15.fork/join框架:ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责存放程序提交给ForkJoinPool的任务,而ForkJoinWorkerThread数组负责执行这些任务。
  RecursiveAction:用于没有返回结果的任务。
  RecursiveTask :用于有返回结果的任务。
 
 1 package tcl.o2o.it.threadinjdk5;
 2 
 3 import java.util.concurrent.ExecutionException;
 4 import java.util.concurrent.ForkJoinPool;
 5 import java.util.concurrent.Future;
 6 import java.util.concurrent.RecursiveTask;
 7 
 8 public class Learn09ForkJoinTest extends RecursiveTask {
 9     private static int ThreadShold = 2;
10     int start;
11     int end;
12 
13     private Learn09ForkJoinTest(int start, int end) {
14         this.start = start;
15         this.end = end;
16     }
17 
18     @Override
19     protected Integer compute() {
20         int sum = 0;
21         boolean flag = (end - start) <= ThreadShold;
22         if (flag) {
23             for (int i = start; i <= end; i++) {
24                 sum += i;
25             }
26         } else {
27             int middle = (start + end) / 2;
28             Learn09ForkJoinTest leftTask = new Learn09ForkJoinTest(start, middle);
29             Learn09ForkJoinTest rightTask = new Learn09ForkJoinTest(middle+1, end);
30 
31             leftTask.fork();//把任务放到该任务的顶部
32             rightTask.fork();
33 
34             int leftResult = (Integer) leftTask.join();//执行完再往下走
35             int rightResult = (Integer) rightTask.join();
36 
37             sum = leftResult + rightResult;
38         }
39         return sum;
40     }
41     public static void main(String[] args) {
42         ForkJoinPool forkJoinPool = new ForkJoinPool();
43         long beginTime = System.currentTimeMillis();
44         Learn09ForkJoinTest task = new Learn09ForkJoinTest(1, 100000);
45         Future<Integer> result = forkJoinPool.submit(task);
46         try {
47             System.out.println(result.get());
48             System.out.println( System.currentTimeMillis() - beginTime);
49         } catch (InterruptedException e) {
50             // TODO Auto-generated catch block
51             e.printStackTrace();
52         } catch (ExecutionException e) {
53             // TODO Auto-generated catch block
54             e.printStackTrace();
55         }
56         
57     }
58 }
View Code

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2017-09-13 18:18  vvning  阅读(145)  评论(0编辑  收藏  举报