一、线程

1、线程创建

  • 继承Thread类创建线程类
  • 实现Runnable接口创建线程类
  • 使用Callable和Future创建线程

Runnable是执行工作的独立任务,但是它不返回任何值,如果希望任务完成时能够返回一个值,可以实现Callable接口

  1. class TestThread implements Callable<Integer> {
  2.  
  3. @Override
  4. public Integer call() throws Exception {
  5. return 1;
  6. }
  7. }
  8.  
  9.   //测试方法
  10. public static void main(String[] args) throws InterruptedException {
  11. ExecutorService exec = Executors.newCachedThreadPool();
  12.  
  13. //submit()的方法声明如下: <T> Future<T> submit(Callable<T> task);
  14. Future<Integer> result = exec.submit(new TestThread());
  15.  
  16. exec.shutdown();
  17. }

2、设置线程优先级

Thread.currentThread().setPriority(int)

Thread类中定义的优先级常量:Thread.MAX_PRIORITY,Thread.MIN_PRIORITY , Thread.NORM_PRIORITY

3、控制线程

Thread.sleep();
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据

Thread.yield();
该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

Thread.join();
如果某个线程调用另一个线程(t)的join方法,此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive() 返回false)。

wait()和notify()、notifyAll()

这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。synchronized关键字用于保护共享数据,阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会访问共享数据呢?此时就用这三个方法来灵活控制。

wait()方法使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。当调用notify()方法后,将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。

notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。

注意:wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法。

后台线程

new Thread().setDaemon(boolean); //必须在线程启动之前调用才能线程设置成后台线程
当最后一个非后台线程终止时,后台线程会“突然”终止。因此一旦main()推出,JVM就会立即关闭所有后台线程

4、线程状态
1、新建(New):当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必需的系统资源,并执行了初始化。此刻线程已经有资格获得CPU时间。之后调度器将把线程转变为可运行状态或阻塞状态。
2、就绪(Runnable):在这种状态下,只要调度器把时间片分配个线程,线程就可以运行。
3、阻塞(Blocked):线程能够运行,但有某个条件阻止它的运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间。直到线程重新进入就绪状态,它才有可能执行操作。
4、死亡(Dead):处于死亡或终止状态的线程将不再是可调度的,并且再也不会得到CPU时间,它的任务已结束。任务死亡的通常方式是从run()方法返回,但是任务的线程还可以被中断。

5、检查中断:Thread.interrupted();

6、未处理的异常

在线程中,一旦异常逃出任务的run方法,它就会向外传播到控制台。要捕获这种错误的异常,可以给每个Thread对象设置异常处理器。
Thread#setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)

  1. Thread t = new Thread();
  2. t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      @Override
      public void uncaughtException(Thread t, Throwable e) {
    System.out.println(e.getCause());
      }
    });
    t.start();  

7、线程同步

基本上所有的并发模式在解决线程冲突的问题的时候,都是采用序列化访问共享资源的方案。
解决资源共享的方法:
synchronized关键字:当任务要执行被此关键字保护的代码段的时候,它将检查锁是否可用,然后获得锁,执行代码,释放锁。所有对象都自动包含单一的锁,当在对象上调用其任意synchronized方法的时候,此对象被加锁,这时该对象上的其他synchronized方法只有等到前一个方法调用完毕并释放了锁之后才能被调用。一个任务可以多次获得对象的锁,比如在调用对象上的某个synchronized方法时,该方法又调用了第二个synchronized方法,此时任务会获得多个锁。JVM负责跟踪对象被加锁的次数,当锁被完全释放,计数为0,当任务第一次给对象加锁时,计数为1,每当这个相同的任务在这个对象上获得锁时,计数会递增。synchronized static 方法可以在类的范围防治对static静态数据的并发访问。
用法:
synchronized void f(){/** … **/}
void g(){ synchronized(object){}}
synchronized static void h(){/** … **/}
注意:在使用并发时,将域设置成private非常重要,否则synchronized关键字就无法防止其他任务直接访问域,导致冲突发生。

使用Lock
Lock对象必须给显式地创建,锁定和释放
用法: 


  1. Lock lock = new ReentrantLock();
    try {
      lock.lock();
      /**

       * do something
    
 */
      return;
    } finally {
      lock.unlock();
    }

注意:lock()的调用必须放置在finally子句中带有unlock()的try-finally语句中,return语句必须放在try子句中出现,以确保unlock()不会过早发生。

原子类AtomicInteger,AtomicLong,AtomicReference... ,常规编程很少会派上用场,但是在涉及性能调优的时候它们就大有用武之地。

Condition:使用互斥并允许任务挂起的基本类,可以通过在Condition上调用await()来挂起一个任务,当外部条件发生变化时,意味着某个任务应该继续执行时,可以调用Condition的signal() 来通知这个任务,从而唤醒一个任务,或者它调用signalAll()来唤醒所有在这个Condition上被其自身挂起的任务。(与Object类的notifyAll() 相比,signalAll()时更安全的方式)

用法:

  1. class Test {
      private Lock lock = new ReentrantLock();
      private Condition condition = lock.newCondition();


      public void t1() {
   
        try {
            lock.lock();
            condition.signalAll();
        } finally {
      lock.unlock();
         }
      }


      public void t2() {
         try {
            lock.lock();
            condition.await();
         } catch (InterruptedException e) {
    
 e.printStackTrace();
         } finally {
    lock.unlock();
         }
      }
    }

8、线程本地存储(ThreadLocal<E>)

线程本地存储是一种自动化机制,可以为使用相同变量的每个不同线程创建不同的存储。比如你有5个线程都要使用变量x所表示的对象,那线程本地存储就会生成5个用于x的不同存储块。
用法:

  1. class Test implements Runnable {
    

 private ThreadLocal<Integer> value = new ThreadLocal<Integer>(){
    private Random rand = new Random(47);
         @Override
         protected Integer initialValue() {
    return rand.nextInt(100);
    
    }
    };


      @Override
      public void run() {
    
 value.get();
         value.set(2);
      }
    }

9、生产者消费者队列
ArrayBlockingQueue:具有固定的尺寸,元素先进先出
LinkedBlockingQueue:无界对列,元素先进先出
用法:

  1. BlockingQueue<Object> arrayQueue = new ArrayBlockingQueue<>(5);
    BlockingQueue<Object> linkedQueue = new LinkedBlockingQueue<>();

BlockingQueue<E>中定义的部分方法:

add(E e):向对列中添加一个元素,成功返回true,空间不足抛出IllegalStateException
offer(E e):向对列中添加一个元素,成功返回true,失败返回false
offer(E e,long timeout,TimeUnit unit):向对列中添加一个元素,成功返回true,失败返回false,空间不足时会等待给定时间后再进行插入
poll(long timeout,TimeUnit unit):返回并删除队头的元素,如果对列是空,会等待给定的时间
put(E e):向对列中添加一个元素,空间不足时会等待,直到有空间以插入新的元素
take(E e):返回并删除队头的元素,如果对列是空,会等待

任务间使用管道进行输入/输出
PipedWriter:允许任务向管道写
PipedReader:允许多个任务从同一个管道中读取
用法:

  1. class Sender implements Runnable {


  2. private Random random = new Random(47);
  3. private PipedWriter writer;
  4. 

 public Sender(PipedWriter writer) {
  5. this.writer = writer;
  6. }
  7. @Override
  8. public void run() {
  9. try {
  10. for (char c = 'A'; c <= 'z'; c++) {
  11. 
 writer.write(c);
  12. TimeUnit.SECONDS.sleep(2);
  13. }
  14. } catch (IOException e) {
  15. e.printStackTrace();
  16. } catch (InterruptedException e){
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21.  
  22. 

class Reseiver implements Runnable {
  23. private PipedReader reader;


  24. public Reseiver(PipedReader reader) {
  25. this.reader = reader;
  26. }


  27. @Override
  28. public void run() {
  29. try {
  30. while (true) {
  31. System.out.println((char)reader.read());
  32. }
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38.  
  39. //测试方法
  40. public static void main(String[] args) throws InterruptedException, IOException {
    ExecutorService exec = Executors.newCachedThreadPool();
    PipedWriter writer = new PipedWriter();
    Sender sender = new Sender(writer);
    Reseiver reseiver = new Reseiver(new PipedReader(writer));
    exec.execute(sender);
    exec.execute(reseiver);
    exec.shutdown();
    }

Java SE5新类库中的构件:
CountDownLatch:用来同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。你可以向CountDownLatch对象设置一个初始值,任务在这个对象上调用await()的方法都将阻塞,直到这个计数值变成0。其他任务在结束其工作时,可以在该对象上调用countDown()来减少这个计数值。CountDownLatch被设计为只触发一次,计数值不能被重置。
用法:

  1. public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    CountDownLatch latch = new CountDownLatch(10);
    
 service.execute(() -> {
    try {
    System.out.println("wait begin");
    latch.await();
    System.out.println("wait end...");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    });


    for (int i = 0; i < 10; i++) {
    service.execute(() -> {
    
 latch.countDown();
    System.out.println("countdown:" + latch.getCount());
    });
    }
    

 service.shutdown();
    

}

CyclicBarrier:有一组任务并行地执行工作,然后在进行下一个步骤前等待,直到所有任务都完成。与CountDownLatch相似,只是CountDownLatch只触发一次,而CyclicBarrier可以多次重用。CyclicBarrier中最重要的方法是await(),当任务调用await()时,线程会被挂起直到所有其他任务都到达barrier(其他任务都调用了await())。CyclicBarrier构造函数可以接受一个barrierAction(Runnable),barrierAction会在所有任务都到达barrier后被执行。
用法:

  1. public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    CyclicBarrier barrier = new CyclicBarrier(10,
    () -> System.out.println("all reach barrier " +
    Thread.currentThread().getName()));


    for (int i = 0; i < 10; i++) {
    
 service.execute(() -> {
    try {
    System.out.println("wait for other" + Thread.currentThread());
    
 barrier.await();
    } catch (InterruptedException e) {
    
 e.printStackTrace();
    } catch (BrokenBarrierException e) {
    e.printStackTrace();
    }
    });
    }


    service.shutdown();
    }

DelayQueue:一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中对象只能在其到期时才能从队列中取走。这个队列是有序的。注意此队列不允许插入null元素。
用法:

  1. class DelayQueueTest implements Runnable, Delayed {
    

 private static int count = 0;
    private int id = count++;
    private int delta;
    private long trigger;
    

 public DelayQueueTest(int delayInMilliseconds) {
    this.delta = delayInMilliseconds;
    this.trigger = System.nanoTime() +
            TimeUnit.NANOSECONDS.convert(
    delayInMilliseconds,
    TimeUnit.MILLISECONDS);
    }
    @Override
    public void run() {
    System.out.println("id:"+id+" delta="+delta);
    }


    @Override
    public long getDelay(TimeUnit unit) {
    return unit.convert(trigger - System.nanoTime(), TimeUnit.NANOSECONDS);
    }
    

 @Override
    public int compareTo(Delayed o) {
    DelayQueueTest that = (DelayQueueTest) o;
    if (this.trigger < that.trigger) {
    return -1;
    }
    if (this.trigger > that.trigger) {
    return 1;
    }
    return 0;
    }
    }
  2.  
  3. //测试方法
  4. public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    DelayQueue<DelayQueueTest> queue = new DelayQueue<>();
    Random random = new Random(47);


    for (int i = 0; i < 10; i++) {
    DelayQueueTest dqt = new DelayQueueTest(random.nextInt(5000));
    
 queue.add(dqt);
    }
    
 service.execute(() -> {
    try {
    while (!Thread.interrupted()){
    queue.take().run();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    });
    
 service.shutdown();
    }

PriorityBlockingQueue:优先级队列,一个无界的BlockingQueue,具有可阻塞的读取操作。优先级队列中的元素是按照优先级顺序从队列中取出。即队头是优先级最高的元素。注意此队列不允许插入null元素。
用法:

  1. class PriorityQueueTest implements Runnable,Comparable<PriorityQueueTest>{
    

 private static int count = 0;
    private int id = count++;
    

 private int priority;
    

 public PriorityQueueTest(int priority) {
    this.priority = priority;
    }


    @Override
    public void run() {
    System.out.println("id:" + id + " priority=" + priority);
    }
    

 @Override
    public int compareTo(PriorityQueueTest o) {
    return this.priority < o.priority ? 1 : (this.priority > o.priority ? -1 : 0);
    }
    }
  2.  
  3. //测试方法
  4. public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    Random random = new Random(47);
    

 PriorityBlockingQueue<PriorityQueueTest> queueTests = new PriorityBlockingQueue<>();
    for (int i = 0; i < 10; i++) {
    
 queueTests.put(new PriorityQueueTest(random.nextInt(200)));
    }
    
 service.execute(() -> {
    try {
    while (!Thread.interrupted()) {
    queueTests.take().run();
    }
    } catch (InterruptedException e) {
    
 e.printStackTrace();
    }
    });
    
 service.shutdown();
    }

二、线程池

使用Executor

常用类及方法说明:
ExecutorService:继承自Executor接口,是一个具有服务生命周期的Executor,例如关闭
Executors:Executor的工厂类或工具方法,包含创建ExecutorService和ScheduledExecutorService等的方法,
常用静态静态方法:
newCachedThreadPool :无边界可回收线程池,当线程池中没有可用的线程时会创建新的线程,如果有可用时会复用可用线程,60秒内没有被使用的线程会被终止
newSingleThreadScheduledExecutor:只有一个线程的线程池,与newFixedThreadPool(1) 不同的地方是它不可以在后续调整线程的数目,而newFixedThreadPool则可以通过ThreadPoolExecutor#setCorePoolSize
newScheduledThreadPool:包含指定数量线程的线程池,任务可以在指定时间后开始执行,并且可以设置周期性执行
newFixedThreadPool:包含指定数量线程的线程池

用法:

  1. ExecutorService exec = Executors.newCachedThreadPool();
  2. ExecutorService exec1 = Executors.newSingleThreadExecutor();
  3. ExecutorService exec2 = Executors.newFixedThreadPool(10);
  4. ExecutorService exec3 = Executors.newScheduledThreadPool(5);

ScheduledThreadPoolExecutor:一个可以在给定时间后执行任务,或周期性执行任务的ThreadPoolExecutor。此类同样实现了ExecutorService接口。

用法:

  1. public static void main(String[] args) throws Exception {
  2. ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(10);
  3. 
scheduler.schedule(() -> {
  4. System.out.println("do something once");
  5. },1000, TimeUnit.MILLISECONDS);
  6.  
  7. scheduler.scheduleAtFixedRate(() -> {
  8. System.out.println("do something periodically");
  9. },1000,1000, TimeUnit.MILLISECONDS);
  10. 
scheduler.shutdown();
  11. }

 

Java并发编程知识总结的更多相关文章

  1. Java工程师学习指南第4部分:Java并发编程指南

    本文整理了微信公众号[Java技术江湖]发表和转载过的Java并发编程相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. [纯干货]Java 并发进阶常见面试题总结 [Java基本功] ...

  2. Java并发编程核心知识体系精讲

    第1章 开宗明义[不看错过一个亿]本章一连串设问:为什么学并发编程?学并发编程痛点?谁适合学习本课?本课程包含内容和亮点?首先4大个理由告诉你为什么要学,其实源于JD岗位要求就不得不服了.其次5个痛点 ...

  3. Java并发编程学习前期知识下篇

    Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...

  4. 多线程(一)java并发编程基础知识

    线程的应用 如何应用多线程 在 Java 中,有多种方式来实现多线程.继承 Thread 类.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实现带 ...

  5. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  6. 学习笔记:java并发编程学习之初识Concurrent

    一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...

  7. Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  8. Java并发编程:同步容器

    Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...

  9. Java并发编程:如何创建线程?

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

随机推荐

  1. Dijkstra--POJ 2502 Subway(求出所有路径再求最短路径)

    题意: 你从家往学校赶,可以用步行和乘坐地铁这两种方式,步行速度为10km/h,乘坐地铁的速度为40KM/h.输入数据的第一行数据会给你起点和终点的x和y的坐标.然后会给你数目不超过200的双向地铁线 ...

  2. Memcached使用

    一.Memcached简介 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网 ...

  3. bzoj 3171 费用流

    每个格拆成两个点,出点连能到的点的入点,如果是箭头指向 方向费用就是0,要不就是1,源点连所有出点,所有入点连 汇点,然后费用流 /********************************** ...

  4. win7 IIS7 PHP环境配置

    PHP5.2.17 官方下载: http://windows.php.net/downloads/releases/php-5.2.17-Win32-VC6-x86.zip PHP5.3.5 官方下载 ...

  5. SQLite中的PRAGMA语句攻略

    原文地址:http://iihero.iteye.com/blog/1189633 PRAGMA语句是SQLITE数据的SQL扩展,是它独有的特性,主要用于修改SQLITE库或者内数据查询的操作.它采 ...

  6. js获取,设置FCKeditor内容

    // 获取编辑器中HTML内容 function getEditorHTMLContents(EditorName) {     var oEditor = FCKeditorAPI.GetInsta ...

  7. Mac中安装maven3.2.1

    Mac中安装maven3.2.1 原文链接:http://blog.csdn.net/f_zongjian/article/details/24144803 本机OS X:10.9,未安装XCode, ...

  8. 简单CSS hack:区分IE6、IE7、IE8、Firefox、Opera

    一.跨浏览器的网页设计一直是让人很头疼的问题,这不只是因为浏览器的版本众多,还有一个重要的原因是相同浏览器的不同时期的版本也会有差异,甚至是在不同操作同台上还会有不同.因此使CSS hack技术进行浏 ...

  9. 1234['toString']['length'] 等于啥?

    首先说该题的答案:1 这是我在一问一答上做的一个选择题,题目虽小,但是包含内容很多,很多网友斥责此题操蛋,恶心.其实只要我们细心的去理解,这段代码有很多值得我们记住的知识点. 1.[]的作用 []是j ...

  10. iOS视频录制裁剪合成

    网址链接: 视频裁剪合并:http://blog.sina.com.cn/s/blog_64ea868501018jx3.html 视频之定义裁剪高宽度:http://www.cocoachina.c ...