Zebra2

Zebra2

复习

  • 进程和线程
    • 进程是程序加载到内存中被cpu计算的过程,进程是资源分配和任务调度的最小单位,引入进程的目的--减少响应时间,提高cpu的利用率。进程的状态:就绪,运行,阻塞。线程本质上是一个简化版的进程,线程是任务执行的最小单位。
  • Bio和Nio
    • BIO是一个阻塞式的IO
    • NIO--基于缓冲区和通道,是非阻塞式的IO---允许数据的双向传输,减少流对象的创建,保证有效的事件交给服务器处理,能够定向的操作特定的数据
  • ByteBuffer
    • 字节缓冲区,底层实际上是一个字节数组--容量位(缓冲区的大小),操作位(用于标识要操作的位置,默认在第0位),限制位(用于限制能达到的最大的位置,默认和容量位是一致的)--反转缓冲区(先将限制位挪到操作位的位置,再将操作位归零)
  • Channel
    • 通道,具有双向性,默认为阻塞的,需要手动设置为非阻塞
  • Selector
    • 选择器,对应的通道必须注册到对应的选择器身上,并且得到对应事件的权限,后边的选择器才会对应管理选择对应的事件

concurrent包

  • 详细介绍请参考http://blog.csdn.net/defonds/article/details/44021605
  • 原文参考:http://tutorials.jenkov.com/java-util-concurrent/index.html
  • 阻塞式队列
    • BlockingQueue
    • FIFO
    • 接口,主要学习实现类--ArrayBlockingQueue和LinkedBlockingQueue
  • 基于生产者和消费者的例子

    • 主函数

      public static void main(String[] args) throws Exception {  
      
          BlockingQueue queue = new ArrayBlockingQueue(1024);  
      
          Producer producer = new Producer(queue);  
          Consumer consumer = new Consumer(queue);  
      
          new Thread(producer).start();  
          new Thread(consumer).start();  
      
          Thread.sleep(4000);  
      } 
      
    • 生产者

      public class Producer implements Runnable{  
      
          protected BlockingQueue queue = null;  
      
          public Producer(BlockingQueue queue) {  
              this.queue = queue;  
          }  
      
          public void run() {  
              try {  
                  queue.put("1");  
                  Thread.sleep(1000);  
                  queue.put("2");  
                  Thread.sleep(1000);  
                  queue.put("3");  
              } catch (InterruptedException e) {  
                  e.printStackTrace();  
              }  
          }  
      } 
      
    • 消费者

      public class Consumer implements Runnable{  
      
          protected BlockingQueue queue = null;  
      
          public Consumer(BlockingQueue queue) {  
              this.queue = queue;  
          }  
      
          public void run() {  
              try {  
                  System.out.println(queue.take());  
                  System.out.println(queue.take());  
                  System.out.println(queue.take());  
              } catch (InterruptedException e) {  
                  e.printStackTrace();  
              }  
          }  
      }  
      - ArrayBlockingQueue
      
    • 添加元素

      package com.peng.queue;
      
      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.BlockingQueue;
      
      import org.junit.Test;
      
      public class BlockingQueueDemo {
          @Test
          public void test1() {
              // 创建
              BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
              // 添加元素
              queue.add("1");
              queue.add("2");
              queue.add("3");
              queue.add("4");
              queue.add("5");
              System.err.println(queue);
          }
      
      }
      
    • 当元素满了以后,再次添加
      • add--异常(full queue)--底层实际调用了offer方法
      • offer--添加成功返回true,添加失败返回false;另一种格式是当在指定时间(元素,时间数量,时间范围)
      • put--阻塞,直到队列有空的地方
  • 不同函数的处理方式
  抛异常 特定值 阻塞 超时
增加 add offer,正常添加返回true,添加事变返回false put offer(o, timeout, timeunit)
删除 队列为空时,remove添加参数正常,不加参数时抛出异常 对列为空时,poll,返回null take poll(timeout, timeunit)在对应的时间尝试删除元素,
检查 element peek    
  • 注意
    • 抛异常:如果试图的操作无法立即执行,抛一个异常。
    • 特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
    • 阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
    • 超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是 true / false)。

LinkedBlockingQueue

  • 底层基于节点的
  • LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。

PriorityBlockingQueue

  • PriorityBlockingQueue 是一个无界的并发队列。它使用了和类 java.util.PriorityQueue 一样的排序规则。你无法向这个队列中插入 null 值。 所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。

ConcurrentMap

  • 接口:想使用的话就得使用它的实现类
  • java.util.concurrent.ConcurrentMap 接口表示了一个能够对别人的访问(插入和提取)进行并发处理的 java.util.Map。ConcurrentMap 除了从其父接口 java.util.Map 继承来的方法之外还有一些额外的原子性方法。
  • 子类ConcurrentHashMap
    • ConcurrentHashMap 和 java.util.HashTable 类很相似,但 ConcurrentHashMap 能够提供比 HashTable 更好的并发性能。在你从中读取对象的时候 ConcurrentHashMap 并不会把整个 Map 锁住。此外,在你向其中写入对象的时候,ConcurrentHashMap 也不会锁住整个 Map。它的内部只是把 Map 中正在被写入的部分进行锁定。另外一个不同点是,在被遍历的时候,即使是 ConcurrentHashMap 被改动,它也不会抛 ConcurrentModificationException。尽管 Iterator 的设计不是为多个线程的同时使用。
    • 例子

      ConcurrentMap concurrentMap = new ConcurrentHashMap();  
      concurrentMap.put("key", "value");  
      Object value = concurrentMap.get("key");  
      

ConcurrentNavigableMap并发导航映射

  • java.util.concurrent.ConcurrentNavigableMap 是一个支持并发访问的 java.util.NavigableMap,它还能让它的子 map 具备并发访问的能力。所谓的 "子 map" 指的是诸如 headMap(),subMap(),tailMap() 之类的方法返回的 map。
  • 方法
    1. headMap(T toKey) 方法返回一个包含了小于给定 toKey 的 key 的子 map
    2. tailMap(T fromKey) 方法返回一个包含了不小于给定 fromKey 的 key 的子 map。
    3. subMap() 方法返回原始 map 中,键介于 from(包含) 和 to (不包含) 之间的子 map

CountDownLatch

  • 闭锁/线程递减锁
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.CountDownLatch;
    
    public class CountDownLatchDemo {
        public static void main(String[] args) throws Exception {
            CountDownLatch cdl = new CountDownLatch(2);
            Thread t1 = new Thread(new Teacher(cdl));
            Thread t2 = new Thread(new Student(cdl));
            t1.start();
            t2.start();
            cdl.await();// 判断递减是否完成了,减为了0?
            System.out.println("可以了,能上课了!");
        }
    }
    
    class Teacher implements Runnable {
        private CountDownLatch cdl = null;
    
        public Teacher(CountDownLatch cdl) {
            super();
            this.cdl = cdl;
        }
    
        @Override
        public void run() {
            System.out.println("老师走进了教室");
            cdl.countDown();// 向下减数
        }
    }
    
    class Student implements Runnable {
        private CountDownLatch cdl = null;
    
        public Student(CountDownLatch cdl) {
            super();
            this.cdl = cdl;
        }
    
        @Override
        public void run() {
            System.out.println("学生走进了教室");
            cdl.countDown();// 向下减数
        }
    
    }
    

CyclicBarrier

  • 栅栏
  • 适合同一个线程类产生的多个线程
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class Tjdemo {
        public static void main(String[] args) {
            // 栅栏--等要等待的线程都到齐了才放行
            CyclicBarrier cb = new CyclicBarrier(4);
            new Thread(new Horse(cb), "黑马").start();
            new Thread(new Horse(cb), "白马").start();
            new Thread(new Horse(cb), "红马").start();
            new Thread(new Horse(cb), "绿马").start();
        }
    }
    
    class Horse implements Runnable {
        private CyclicBarrier cb = null;
    
        public Horse(CyclicBarrier cb) {
            super();
            this.cb = cb;
        }
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "走到了起点,准备赛马");
            try {
                cb.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("听到声音," + Thread.currentThread().getName() + "跑了 出去~~");
        }
    
    }
    

Exchange

  • 交换机
  • 交换两个线程的信息
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.Exchanger;
    
    public class ExchangeDemo {
    
        public static void main(String[] args) {
            Exchanger<String> ex = new Exchanger<String>();
    
            new Thread(new Spy1(ex)).start();
            new Thread(new Spy2(ex)).start();
        }
    }
    
    // 间谍1--交换信息
    class Spy1 implements Runnable {
        private Exchanger<String> ex = null;
    
        public Spy1(Exchanger<String> ex) {
            this.ex = ex;
        }
    
        @Override
        public void run() {
            String s1 = "地瓜,地瓜,我是土豆!";
            try {
                String sp2_info = ex.exchange(s1);
                System.out.println("间谍2传给1:" + sp2_info);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    // 间谍2--交换信息
    class Spy2 implements Runnable {
        private Exchanger<String> ex = null;
    
        public Spy2(Exchanger<String> ex) {
            this.ex = ex;
        }
    
        @Override
        public void run() {
            String s2 = "土豆土豆,我是地瓜!";
            try {
                String sp1_info = ex.exchange(s2);
                System.out.println("间谍1传给2:" + sp1_info);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

Semaphore

  • 信号量
  • 保护一个重要(代码)部分防止一次超过N个线程进入
  • 在两个线程之间发送信号
  • 限制一段时间内在某个时间段内最多只能有n个线程进入访问,每个线程的进入的时候,先进行acquire操作,信号量减少一个,减到0阻塞;release释放信号量,信号量的个数增加
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.Semaphore;
    
    public class SemphoreDemo {
        public static void main(String[] args) {
            // 信号量
            Semaphore se = new Semaphore(5);
            for (int i = 0; i < 10; i++) {
                new Thread(new WhatFilm(se)).start();
            }
        }
    }
    
    class WhatFilm implements Runnable {
        private Semaphore se = null;
    
        public WhatFilm(Semaphore se) {
            this.se = se;
        }
    
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            try {
                se.acquire();// 把信号量减少一个
                System.out.println(name + "取了一副眼镜,进场看电影!");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "归还了眼镜");
            se.release();// 释放信号量
        }
    
    }
    

ExecutorService

  • 先交给核心线程处理,如果核心线程已经用完,再来的请求放入工作队列中,
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class ExecutorServiceDemo {
        public static void main(String[] args) {
            // corePoolSize--核心池的大小--一旦创建,不再销毁
            // maximumPoolSize--允许存在的最大线程数量(临时线程)
            // keepAliveTime--线程存活的时间
            // unit--时间单位
            // workQueue--工作队列,阻塞式队列
            // handler--
            // 核心池的大小
            ExecutorService es = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));
            for (int i = 0; i < 15; i++) {
                es.submit(new EDemo());
            }
            es.shutdown();
        }
    }
    
    class EDemo implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "正在处理中!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    

newCachedThreadPool和newFixedThreadPool

  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class PoolDemo {
        public static void main(String[] args) {
            // 缓存线程池
            // --核心线程池的数量为0
            // --临时线程存活的时间比短(一分钟)【好处:能够很好的应对高并发的场景】【缺点:不适合长任务的场景】
            // --只有一个线程
            // --小队列大池子的线程池
            ExecutorService es1 = Executors.newCachedThreadPool();
    
            // 大队列小池子的线程池
            // 没有临时线程,都是核心线程【优点:适合长任务的场景】【缺点:不适合短任务的场景】
            // 降低服务器的并发压
            ExecutorService es2 = Executors.newFixedThreadPool(5);
            Future<String> result = es2.submit(new Cdemo());
            es2.shutdown();
    
        }
    }
    
    class Cdemo implements Callable<String> {
        @Override
        public String call() throws Exception {
            for (int i = 0; i < 10; i++) {
                System.out.println("lala--" + i);
            }
            return "success";
        }
    
    }
    

执行线程函数的区别

  • submit
    • 有返回值
    • 可以执行的线程
      • Callable
      • Runnable
  • execute
    • 没有返回值
    • 可以执行的线程
      • Runnable

Lock

  • 和Syschronized(非公平)机制类似,但是比Syschronized更加灵活
  • 策略
    1. 公平策略:每个线程都有机会执行到
    2. 非公平策略

ReentrantLock

  • 默认是一个非公平的锁
  • 可以设置为公平锁
  • 上锁-lock
  • 解锁-ulock
  • 可以一个方法加锁,另一个方法解锁---可以跨方法来用锁

Lock和synchronized的区别

  • 锁的时间
    • 同步块不能用
    • lock可以
  • 在不同的方法里调用
    • 同步块不可以
    • lock可以
  • synchronized代码块不能够保证进入访问等待的线程的先后顺序
  • 不能传递任何参数给一个synchronized代码块的入口,因此,对于synchronized代码块的访问等待设置超时时间是不可能的事情

Lock方法

  • lock()
    • lock将Lock实例锁定,如果该Lock实例已被锁定,调用lock()方法的线程将会阻塞,直到Lock实例解锁
  • lockInterruptibly()
    • 方法将会被调用的线程锁定,除非该线程被打断,此外,如果一个线程在通过这个方法来锁定Lock对象时进入阻塞等待,而它被打断了的话,该线程将会退出这个方法的调用
  • tryLock()
    • 该方法试图立即锁定Lock实例,如果锁定成功,它将返回true,如果Lock实例已经锁定 该方法返回false,这一方法永不阻塞
  • tryLock(Long timeout,TimeUnit timeUnit)
    • 工作类似于tryLock方法,除了它在放弃lock之前等待一个给定的时间之外
  • unlock
    • 该方法对Lock实例解锁,一个Lock实现将只允许锁定了该对象的线程来调用此方法,其他(没有锁定该lock 对象的线程)线程对unlock方法的调用则会抛出一个未检查异常(RuntimeException)

ReadWriteLock

  • 是一种比较先进的锁
  • 同一时刻允许多个线程来读取同一个资源,但是只能一个线程来写操作
  • 在读期间,不允许进行写操作;在写期间,不允许读

原子操作

  • 数据操作只允许一个线程来操作
  • eg:PAtomicInteger 类为我们提供了一个可以进行原子性读和写操作的 int 变量,它还包含一系列先进的原子性操作,比如 compareAndSet()。AtomicInteger 类位于 java.util.concurrent.atomic 包,因此其完整类名为 java.util.concurrent.atomic.AtomicInteger。本小节描述的
  • 例子

    package com.peng.lock;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class YzDemo {
        public static int count = 0;
    
        // 原子操作
        public static AtomicInteger ai = new AtomicInteger(0);
    
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch cd = new CountDownLatch(2);
            new Thread(new Ademo(cd)).start();
            new Thread(new Ademo(cd)).start();
            cd.await();
            System.out.println(ai);
        }
    
    }
    
    class Ademo implements Runnable {
        private CountDownLatch cd = null;
    
        public Ademo(CountDownLatch cd) {
            this.cd = cd;
        }
    
        @Override
        public void run() {
            for (int i = 1; i <= 1000; i++) {
                YzDemo.ai.incrementAndGet();
            }
            cd.countDown();
        }
    
    }

猜你喜欢

转载自blog.csdn.net/eieiei438/article/details/79404879