Thinking In Java并发

***使用并发时要多疑而自信 ***

线程的运行态.png

Executor(p656)

使用执行器Executor来管理Thread对象,简化了并发编程,Executor在客户端和任务执行器之间提供了一个间接层,与客户端执行任务不同,这个中介对象执行任务,使用Executor,可以管理异步任务的执行,无须显示的管理线程的生命周期。

** 非常常见的情况是使用单个Executor用来创建和管理系统中的所有任务**


ExecutorService ------- 具有生命周期的Executor(具有execute shutdown等方法)

**可以直接创建一个Executor(new一个你所需要的线程池) 或者使用Executor的静态方法来创建一个ExecutorService **

Executors类型
  • newCachedThreadPool
    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool
    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool
    创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
从任务中产生返回值(p658)

实现Callable接口而不是Runnable接口,Callable是一个具有类型参数的泛型,要使用ExecutorServicesubmit方法来调用它,submit()返回一个Future对象。

休眠

影响任务行为的一种简单方法是调用sleep(),会让任务中止执行给定的时间

 TimeUnit.MILLISECONDS.sleep(100);  //毫秒
优先级/让步(p660)

优先级仅仅决定频率使用setPriority 设置优先级 (尽管jdk有十个优先级,但是唯一可移植的方法当调整优先级的时候,只使用MAX,NORM,MIN这三个级别)
任何重要的控制手段,都不能依赖于yield

后台线程(p662)

在程序运行时在后台提供一种通用服务的线程,而且这种线程并不是程序中不可或缺的一部分,因此,所有的非后台线程结束时,程序也中止了,同时会杀死进程中的所有后台线程。可以通过isDaemon()来确定一个线程是否为后台线程
必须在线程启动之前调用.setDaemon(true),才能启动后台线程

线程工厂

ThreadFactory 通过实现TreadFactory或者new 一个ThreadFactory对象,可以定制由Executor创建线程的属性,每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,使用这个对象来创建新的线程。

加入一个线程(p669)

一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行,如果某个线程在一个线程t上调用t.join,此线程将被挂起,直到目标线程t结束才恢复(即为t.isAlive()返回为假)。也可以在调用join的时候带上一个超时参数,这样如果目标线程在这段时间内还没有结束的话,join()方法总能返回。
对join方法的调用可以被中断,做法是在调用的线程上调用interrupt()方法,会使用到try-catch

捕获异常(p672)

由于线程的本质特性,使得你不能捕获从线程中逃逸的异常,一旦异常逃出任务的run()方法,它会向外传播到控制台。在se5中 可以使用Executor来解决这个问题。
Java se5之后出现了新接口Handler,它允许你在每一个Thread对象上都附着一个异常处理器Thread.UncaughtExceptionHandler.uncaughtException会在线程因未捕获的异常而临近死亡时被调用,为了使用它,我们可以创建一个新类型的线程工厂,它将在每个新创建的Thread对象附着一个Thread.UncaughtExceptionHandler ,再将这个线程工厂传给Executor

class ExceptionThread2 implements Runnable {
  public void run() {
    Thread t = Thread.currentThread();
    System.out.println("run() by " + t);
    System.out.println(
      "eh = " + t.getUncaughtExceptionHandler());
    throw new RuntimeException();
  }
}

class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
    System.out.println("caught " + e);
  }
}

class HandlerThreadFactory implements ThreadFactory {
  public Thread newThread(Runnable r) {
    System.out.println(this + " creating new Thread");
    Thread t = new Thread(r);
    System.out.println("created " + t);
    t.setUncaughtExceptionHandler(
      new MyUncaughtExceptionHandler());
    System.out.println(
      "eh = " + t.getUncaughtExceptionHandler());
    return t;
  }
}
解决共享资源竞争(p676)

关键字synchronized :当任务要执行到被synchronized保护的代码片段的时候,它将检查锁是否可用,然后获取锁,执行代码,释放锁。

共享资源一般是以对象的形式存在的内存片段,也可以是文件、输入/输出端口或者是打印机。要控制对共享资源的访问,得先把它包装进一个对象,然后把所有要访问的这个资源的方法标记为synchronized,如果某个任务处于一个对标记为synchronized的方法的调用中,那么在这个线程从该方法返回之前,其他所有要调用类中任何标记为synchronized方法的线程的都会被阻塞。

所有对象都自动的含有单一的锁(监视器)。当在对象上调用任意synchronized方法的时候,此对象都会被加锁,这时该对象上的其他synchronized方法只有等前一个方法调用完毕并释放锁之后才能被调用。所以,对于某一个特定的对象来说,其所有的synchronized方法共享一个锁,这可以被用来防止多个任务同时访问被编码为对象的内存。

使用并发时应当将域设置为private,否则synchronized关键字就不能防止其他 任务直接访问域,这样会产生冲突

一个任务多次获取锁(p677)

一个任务可以多次获得对象的锁,如果一个方法在同一个对象上调用的第二个方法,后者又调用了同一个对象上的另一个方法,就会出现这种情况 //????没懂。

针对类的锁

针对每一个类,也有一个锁(作为类的class对象的一部分),所以synchronized static方法可以在类的范围内防止对static数据的并发访问。

使用显示的Lock对象(p678)

Lock对象必须被显示的创建,锁定和释放,因此他和内建锁形式相比,代码缺乏优雅性,但是, 对于解决某些类型的问题来说,它更加灵活。

原子性与易变性(p680)

原子操作是不能被线程调度机制中断的操作,一旦操作开始,他一定可以在可能发生的切换到其他线程之前执行完毕

原子性可以应用于除long和double之外的所有基本类型之上的简单操作,对于读写除long和double之外的基本变量这样的操作,可以保证他们会被当做不可分的操作开操作内存,但是jvm可以将64位(long和double)的读取和写入当做两个分离的32位操作来执行,这就产生了一个读取和写入操作中间的上下文切换,从而导致不同的任务会看见不正确的结果的可能性(称为字撕裂),但是如果你定义long和double的时候使用volatile关键字,就会获得(简单赋值与返回操作的原子性)

volatile

volatile关键字还确保了应用中的可视性,如果你将一个域声明为volatile,只要对这个域产生了写操作,所有的读操作就都可以看见这个修改

原子类

AtomicInteger,AtomicLong, AtomicReference

线程本地存储(p691)

防止任务在共享资源上产生冲突的第二种方式是根除对变量的共享,线程本地存储是一种自动化机制,可以为使用相同变量的每一个不同的线程都创建不同的存储,因此,如果你有5个线程都要使用变量x所表示的对象,那线程本地存储就会生成5个用于x的不同存储块,主要是,他们可以将状态与线程关联起来。

在android的消息处理机制就使用了ThreadLocal

可以总结为一句话:ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。举个例子,我出门需要先坐公交再做地铁,这里的坐公交和坐地铁就好比是同一个线程内的两个函数,我就是一个线程,我要完成这两个函数都需要同一个东西:公交卡(北京公交和地铁都使用公交卡),那么我为了不向这两个函数都传递公交卡这个变量(相当于不是一直带着公交卡上路),我可以这么做:将公交卡事先交给一个机构,当我需要刷卡的时候再向这个机构要公交卡(当然每次拿的都是同一张公交卡)。这样就能达到只要是我(同一个线程)需要公交卡,何时何地都能向这个机构要的目的。
有人要说了:你可以将公交卡设置为全局变量啊,这样不是也能何时何地都能取公交卡吗?但是如果有很多个人(很多个线程)呢?大家可不能都使用同一张公交卡吧(我们假设公交卡是实名认证的),这样不就乱套了嘛。现在明白了吧?这就是ThreadLocal设计的初衷:提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程。

是编程思想的读书笔记,持续更新。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容