zoukankan      html  css  js  c++  java
  • 多线程学习

    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
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    岁月本长而忙者自促;天地本宽而卑者自隘;风花雪月本闲,而劳忧者自冗;天行健,君子以自强不息;地势坤,君子以厚德载物;宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒.不妄取,不妄予,不妄想,不妄求,与人方便,随遇而安
  • 相关阅读:
    JavaScript之面向对象与原型笔记整理--------创建对象(1)
    PTA乙级 (*1030 完美数列 (25分))
    PAT乙级 (1033 旧键盘打字 (20分)(字母大小写转换、判断是否为大小写字母数字))
    PTA乙级 (*1040 有几个PAT (25分))
    PTA乙级 (1042 字符统计 (20分))
    PTA乙级 (1043 输出PATest (20分))
    PTA乙级 (1048 数字加密 (20分))
    PTA乙级 (1049 数列的片段和 (20分))
    PTA乙级 (1051 复数乘法 (15分))
    PTA乙级 (*1054 求平均值 (20分))
  • 原文地址:https://www.cnblogs.com/vvning/p/7516605.html
Copyright © 2011-2022 走看看