精华内容
下载资源
问答
  • Java 并发编程实战

    2018-07-26 23:39:58
    Java 并发编程实战,喜欢或者经常碰到线程处理的朋友可以关注并下载
  • Java并发编程实战》PDF版本下载
  • 声明:Java并发的内容是自己阅读《Java并发编程实战》和《Java并发编程的艺术》整理来的。 图文并茂请戳 思维导图下载请戳 目录 (1)基础概念 (2)线程 (3)锁 (4)同步器 (5)并发容器和框架 (6)Java并发工具...

    声明:Java并发的内容是自己阅读《Java并发编程实战》和《Java并发编程的艺术》整理来的。

    这里写图片描述

    图文并茂请戳

    思维导图下载请戳

    目录

    (1)基础概念

    (2)线程

    (3)锁

    (4)同步器

    (5)并发容器和框架

    (6)Java并发工具类

    (7)原子操作类

    (8)Executor框架(执行机制)

    (9)其他


    (一).基础概念

    1.可见性和原子性

    • 可见性:一个线程修改了共享变量的值,另一个线程可以读到这个修改的值。

    • 原子性:不可被中断的一个或一系列操作。

    如何保障原子性:

    • 使用总线锁保证原子性。

    • 使用缓存锁保证原子性。

    2.原子操作的三种实现:

    (1).CAS(Compare And Swap 比较与交换)

    需要输入两个数值(一个旧值和一个新值),在操作期间先比较旧值有没有发生变化,如果没有发生变化,才交换成新值,如果发生了变化就不交换。

    存在的三大问题:

    • ABA问题:如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际是发生了变化。解决方案:1.使用版本号,在变量前面追加版本号,每次变量更新都把版本号加1。JDK提供的类:AtomicStampedReference。

    • 循环时间长开销大。

    • 只能保证一个共享变量的原子操作。
      解決方案:JDK提供AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里进行CAS操作。

    (2).锁

    (3).JDK并发包的支持

    如:AtomicBoolean(用原子方式更新的boolean值),

    AtomicInteger(用原子方式更新的int值),

    AutomicLong(用原子方式更新的long值)。

    3.同步原语

    (1).volatile

    特点:

    • 可见性:对一个volatile变量的读,总是能看到任意线程对这个volatile变量最后的写入。

    • 原子性:对任意单个volatile变量的读/写具有原子性。

    • 从内存语义角度:volatile的写-读与锁的释放-获取有相同的内存效果。

    • 为了实现volatile的内存语义,编译期在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

    • 从编译器重排序规则和处理器内存屏障插入策略来看,只要volatile变量与普通变量之间的重排序可能会破坏volatile的内存语义,这种重排序就会被编译器重排序规则和处理器内存屏障插入策略禁止。

    实现原理:

    • 将当前处理器缓存行的数据回写到系统内存。

    • 写回内存的操作会使其他CPU里缓存该内存地址的数据无效。

    (2).synchronized

    不同情況锁住的对象:

    • 对于普通同步方法,锁是当前实例对象。

    • 对于静态同步方法,锁是当前类的Class对象。

    • 对于同步方法块,锁是Synchronized括号里配置的对象。

    (3)final

    
    public class FinalExample {
    
    	int i;                     //普通变量
    	final int j;               //final变量
    	static FinalExample obj;
    	
    	public FinalExample() {    //构造函数
    		i = 1;                 //写普通域
    		j = 2;                 //写final域
    	}
    	
    	public static void writer() {
    		obj = new FinalExample();
    	}
    	
    	public static void reader() {
    		FinalExample object = obj;    //读对象引用
    		int a = object.i;             //读普通域
    		int n = object.j;             //读final域
    	}
    }
    
    
    • 写final域的重排序规则:JMM禁止将final域的写重排序到构造函数之外。
    • 读final域的重排序规则:在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作。

    4.Java内存模型(JMM)

    5.重排序

    重排序的3种类型:

    • 编译器优化的重排序。

    • 指令级并行的重排序。

    • 内存系统的重排序。

    编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

    6.顺序一致性

    顺序一致性内存模型两大特征:

    • 一个线程中的所有操作必须按照程序的顺序来执行。

    • (不管程序是否同步)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见。

    7.happens-before与as-if-serial

    JMM对happens-before的设计原则:只要不改变程序的执行结果(指的是单线程程序和正确同步的多线程程序),编译器和处理器怎么优化都行。

    happens-before关系的定义:

    (1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

    (2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么JMM允许这种重排序。

    as-if-serial:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。

    區別:as-if-serial语义保障单线程内程序的执行结果不被改变,happens-before关系保证正确同步的多线程程序的执行结果不被改变。

    8.双重检查锁定与延迟初始化

    使用双重检查锁延迟初始化

    
    public class DoubleCheckedLocking {                         
    	
    	private static DoubleCheckedLocking instance;           
    	
    	public static DoubleCheckedLocking getInstance() {      
    		if(null == instance) {                              
    			synchronized(DoubleCheckedLocking.class) {      
    				if(null == instance) {                      
    					instance = new DoubleCheckedLocking();  
    				}
    			}
    		}
    		return instance;
    	}
    }
    
    

    线程A-A1:分配对象的内存空间。
    线程A-A2:设置instance指向内存空间。
    线程B-B1:判断instance是否为空。
    线程B-B2:由于instance不为null,线程B将访问instance引用的对象。
    线程A-A3:初始化对象
    线程A-A4:访问instance引用的对象。

    存在的问题:
    A2和A3重排序,线程B访问到一个还没初始化的对象。

    解决方案:

    • 将instance变量声明为volatile型的。通过禁止重排序来保证线程安全的延迟初始化。

    • 通过不允许其他线程”看到“这个重排序实现线程安全的延迟初始化。

    
    public class InstanceFactory {
    
    	private static class InstanceHolder {
    		public static InstanceFactory instance = new InstanceFactory();
    	}
    	
    	public static InstanceFactory getInstance() {
    		return InstanceHolder.instance;
    	}
    }
    
    

    9.生产者-消费者模式


    (二).线程

    1.什么是线程?

    现代操作系统在运行一个程序时,会为其创建一个进程。现代操作系统调度的最小单元是线程,也叫轻量级进程。在一个进程里可以创建多个线程,这些线程都拥有各自的计数器,堆栈和局部变量等属性。

    2.创建线程的三种方式

    (1).Thread

    
    @Test
    
    public void testThread() {
    
    	Thread thread = new Thread("myThread");
    	thread.start();
    }
    
    

    (2).Runnable

    
    @Test
    public void testRunnable() {
    	Thread thread = new Thread(new Runnable() {
    
    		@Override
    		public void run() {
    			System.out.println("myThread");
    		}
    		
    	});
    	thread.start();
    }
    
    

    (3).Callable

    
    @Test
    
    public void testFutureTask() throws InterruptedException, ExecutionException {
    
    	ExecutorService executorService = Executors.newFixedThreadPool(2);
    	Future<String> future = executorService.submit(new Callable<String>() {
    
    		@Override
    		public String call() throws Exception {
    			return "Hello,World!!!";
    		}
    		
    	});
    	String result = future.get();
    	System.out.println(result);
    	executorService.shutdown();
    	
    }
    
    

    3.Daemon线程

    • Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。
    • 当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。
    • 可以通过调用Thread,setDaemon(true)将线程设置为Daemon线程。

    4.等待/通知机制

    等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。

    等待方遵循如下规则:

    • 获取对象的锁

    • 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。

    • 条件满足则执行对应的逻辑。

    
    while(条件不满足){
        对象.wait();
    }
    
    //处理对应的逻辑
    
    

    通知方遵循如下规则:

    • 获得对象的锁。

    • 改变条件

    • 通知所有等待在对象上的线程。

    
    synchronized(对象){
    
            //改变条件
           对象.notifyAll();
    
    }
    
    

    5.Thread.join()

    当前线程A要等待thread线程终止之后才能从thread.join()返回。

    6.ThreadLocal

    ThreadLocal,即线程变量,是一个以ThreadLocal对象为键,任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定到这个线程上的一个值。

    7.线程的终止、中断

    (1).Thread.interrupt:中断线程

    • 除非线程正在进行中断它自身,否则都会接受这个方法的中断。会调用Thread.checkAccess(),可能会抛出SecurityException。

    • 如果线程调用了Object.wait(),Thread.sleep(),Thread.join()处于阻塞状态,那它的堵塞状态会被清除,并得到一个InterruptedException。

    • 如果线程在InterruptibleChannel上的I/O操作中被中断,通道会被关闭,线程的中断状态会被设置,并得到一个ClosedByInterruptedException。

    (2).Thread.interrupted:测试当前线程是否被中断。

    清除线程的中断状态。如果连续调用两次这个方法,第二次调用会返回false(除非当前线程再次被中断,在第一次调用清除它的中断状态之后,并且在第二次调用检查它之前)。

    (3).Thread.isInterrupted:测试某个线程是否被中断

    中断状态是否被重置取决于传入的值。


    (三).锁

    锁是Java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。

    1.锁的内存语义:

    • 利用volatile变量的写-读所具有的内存语义。

    • 利用CAS所附带的volatile读和volatile写的内存语义。

    2.重入锁

    (1).什么是重入锁?
    支持重进入的锁,表示锁能够支持一个线程对资源的重复加锁。重入锁支持获取锁时的公平性和非公平性选择。

    (2).解决两个问题:

    • 线程再次获取锁:锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次获取锁。

    • 锁的最终释放:锁的最终释放要求锁对于锁获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经释放。

    3.排他锁:ReentrantLock

    (1)公平锁:

    • 公平锁释放时,最后要写一个volatile变量state。

    • 公平锁获取时,首先会去读volatile变量。

    (2)非公平锁:

    • 非公平锁释放时,最后要写一个volatile变量state。

    • 非公平锁获取时,首先会用CAS(CompareAndSet)更新volation变量,这个操作同时具有volatile写和volatile读的内存语义。

    (3)公平锁与非公平锁的区别

    公平性与否是针对获取锁而言的。

    • 公平锁:如果一个锁是公平的,那么获取锁的顺序就应该符合请求的绝对时间顺序,也就是FIFO。

    • 非公平锁:刚释放锁的线程再次获取同步状态的几率会非常大,使得其他线程只能在同步队列中等待。

    公平性锁保证了锁的获取按照FIFO原则,而代价是进行大量的线程切换。非公平性锁虽然可能造成”饥饿“,但极少的线程切换,保证其更大的吞吐量。

    4.Lock

    (1)读写锁:ReentrantReadWriteLock

    读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被堵塞。

    读写锁的实现分析:

    • 读写状态的设计:同步状态表示锁被一个线程重复获取的次数,而读写锁的自定义同步需要在同步状态(一个整型变量)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。

    • 写锁的获取与释放:写锁是一个支持重进入的排它锁。如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取写锁时,读锁已经被获取(读状态不为0)或者该线程不是已经获取写锁的线程,则当前线程进入等待状态。

    • 读锁的获取与释放:如果当前线程已经获取了读锁,就增加读状态。如果当前线程在获取读锁时,写锁已被其他线程获取,则进入等待状态。

    • 锁降级:锁降级指的是写锁降级为读锁。指把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前拥有的)读锁的过程。

    锁的四种状态:无锁,偏向锁,轻量级锁,重量级锁

    5.LockSupport工具

    当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应的工作。

    6.Condition接口

    Condition接口提供了类似Object的监视器方法(包括wait(),wait(long timeout),notify(),以及notifyAll()方法),与Lock配合可以实现等待/通知模式。

    Condition的实现:等待队列,等待和通知。

    • 等待队列:等待队列是一个FIFO队列,在队列中的每一个节点都包含了一个线程引用,该线程是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程会释放锁,构造成节点加入等待队列并进入等待状态。

    • 等待:调用Condition的await()方法(或者以await开头的方法),会使当前线程进入等待队列并释放锁,同时线程状态变为等待状态。当从await()方法返回时,当前线程一定获取了Condition相关的锁。

    • 通知:调用Condition的signal()方法,将会唤醒在等待队列中等待时间最长的节点(首节点),在唤醒节点之前,会将节点移步到同步队列。

    7.避免活跃性危险

    (1).死锁

    • 哲学家用餐问题:每个线程都拥有别的线程需要的资源,同时又等待别人拥有的资源,在获得别的资源之前不会释放自己手上的资源。

    • 数据库事务死锁:数据库如果发生死锁,会选择一个事务释放资源。

    • 锁顺序死锁:线程A,B都需要锁1,2。线程A先获得锁1 ,再请求锁2 ,线程B先获得锁2,再请求锁1 。

    8.死锁的避免与诊断

    (1).内置锁:只要没有获得锁,就会一直等待下去。

    (2).定时锁:使用Lock类的定时tyLock功能。可以指定一个超时时限,在等待超过该时间后会返回失败信息。

    (3).线程转储

    避免死锁的四种方式:

    • 避免一个线程同时获得多个锁。

    • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只获得一个资源。

    • 使用定时锁。

    • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

    9.饥饿,糟糕的响应性,活锁

    • 饥饿:线程由于无法访问它需要的资源而不能继续执行,引发饥饿最常见的资源是CPU时钟周期。

    • 活锁通常发送在处理事务消息的应用程序中,如果不能成功地处理事务消息,那么消息机制将回滚整个事务,将这个事务放在等待队列的开头。

    • 当多个相互协作的线程都对彼此响应从而修改各自的状态,并使得任何一个线程都无法继续执行时,就发生了活锁。

    • 在并发应用中,通过等待随机长度的时间和回退可以有效地避免活锁的发生。


    (四).同步器

    (1).实现

    • 同步队列:同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获得同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。

    • 独占式同步状态获取与释放:在获取同步状态时,同步器维护一个队列,获取状态失败的线程会被加入队列中并在队列中进行自旋,移除队列的原因时自旋获取了同步状态且前驱节点时头节点。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,然后唤醒头节点的后继结点。

    • 共享式同步状态获取与释放:共享式获取与独占式获取最主要的区别在于同一时刻能否有多个线程同时获取同步状态。

    • 独占式超时获取同步状态:在指定的时间段内获取同步状态,如果获取到同步状态返回true,否则,返回false。

    (2).AbstractQueuedSynchronized

    用来构建锁或者其他同步组件的基础框架,使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

    提供了三个对同步状态进行修改的方法:

    • getState():获取当前同步状态。

    • setState(int new3State):设置当前同步状态。

    • compareAndSetState(int export,int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。


    (五).并发容器和框架

    (1).ConcurrentHashMap

    与HashMap,HashTable对比:

    • HashMap是线程不安全,且可能导致程序死循环。

    • HashTable效率低下。

    • ConcurrentHashMap的锁分段技术可有效提升访问效率。首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段的数据的时候,其他段的数据也能被其他线程访问。

    ConCurrentHashMap的结构:ConCurrentHashMap是由Segment数组结构和HashEntry数组结构组成。

    (2).ConcurrentLinkedQueue

    ConcurrentLinkedQueue由head节点和tail节点组成,每个节点(Node)由节点元素(item)和指向下一个节点(next)的引用组成,从而组成一张链表结构的队列。

    (3).阻塞队列

    • 插入:当队列满时,队列会堵塞插入元素的线程,直到队列不满。

    • 移除:当队列为空,获取元素的线程会等待线程为非空。

    实现原理:
    使用通知模式实现。当生产者往满的队列里添加元素时会堵塞生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。

    1.ArrayBlockingQueue

    • 数组实现的有界阻塞队列,按照先进先出的原则对元素进行排序。

    2.LinkedBlockingQueue

    • 继承了AbstractQueue类,实现了BlockingQueue接口。

    • 采用先进先出的排列方式,头结点是入队时间最长的元素,尾结点是入队时间最短的元素。新结点添加到队尾,从队头弹出结点。

    • 链表队列的特点是:跟基于数组的队列相比有更大的吞吐量,但在大多并发应用中性能会比较差。

    • LinkedBlockingQueue可以在创建的时候传递一个容量参数,限制队列的长度,不设定的情况下,默认是Integer.MAX_VALUE。在没有超过队列边界的情况下,每次添加会自动创建链表结点。

    3.PriorityBlockingQueue

    • 是一个支持优先级的无界阻塞队列。默认情况下时自然顺序升序排序。

    4.SychronousQueue

    • SynchronousQueue是一个不存储元素的堵塞队列,每一个put操作必须等待一个take操作,否则不能继续添加元素。

    5.DelayQueue

    • 延迟队列:无界队列,只有延迟过期的任务才能加入队列。队列的队首元素是在过去延迟过期最长的元素。如果没有延迟到期,队列中就没有元素,调用poll方法会返回null。当调用元素的getDelay(TimeUnit.NANOSECONDS)方法返回等于或小于0的值时,出现到期。

    • DelayQueue的应用场景:a.缓存系统:把需要缓存的元素加入DelayQueue中,让一个线程循环测试是否能从DelayQueue中获取元素,能表示缓存到期。b.定时任务调度。

    • Timer和DelayQueue的区别?Timer只能处理单个后台线程,而DelayQueue可以处理多个。

    6 . LinkedTransferQueue

    • LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。

    7 . LinkedBlockingDeque

    • 一个由链表结构组成的双向阻塞队列,可以运用在“工作窃取”模式中。

    (4).Fork/Join框架

    用于并行执行任务,把一个大任务分割成小任务,再把每个小任务的结果汇总成大任务结果。Fork是把一个大任务切分成若干子任务并行执行,Join是合并这些子任务的执行结果。

    (5).工作窃取算法

    指某个线程从其他队列里窃取任务来执行。为了减少窃取任务线程和别窃取任务线程之间的竞争,使用双端队列,被窃取任务线程从双端队列的头部拿任务执行,窃取任务线程从双端队列的尾部拿任务执行。

    • 工作窃取算法的优点:充分利用线程进行并行计算,减少线程间的竞争。

    • 工作窃取算法的缺点:在某些情况下还是存在竞争,比如双端队列里只有一个任务时,并且该算法会消耗更多的系统资源,比如创建多个线程和多个双端队列。


    (六).Java并发工具类

    1.CyclicBarrier

    一组线程在到达一个屏障(同步点)前被堵塞,直到最后一个线程到达屏障时,屏障才会放行,这组线程才能继续执行。

    应用场景:可以用于多线程计算数据,最后合并计算结果。

    CyclicBarrier与CountDownLatch的区别:CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。CountDownLatch的计数是减法,CyclicBarrier的计数是加法。

    2.Semaphore

    用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公共资源。

    应用场景:可以用于流量控制,特别是公共资源有限的应用场景,比如数据库连接。

    3.CountDownLatch

    允许一个或多个线程等待其他线程完成操作。

    4.Exchanger

    Exchanger是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,会一直等待第二个线程也执行exchange()方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。

    应用场景:用于遗传算法。


    (七).原子操作类

    1.原子更新基本类型类

    • AtomicBoolean

    • AtomicInteger

    • AtomicLong

    2.原子更新数组

    • AtomicIntegerArray

    • AtomicLongArray

    • AtomicReferenceArray

    3.原子更新引用类型

    • AtomicReference

    • AtomicReferenceFieldUpdater 原子更新引用类型里的字段

    • AtomicMarkableReference 原子更新带有标记位的引用类型。

    4.原子更新字段类

    • AtomicIntegerFieldUpdater 原子更新整型的字段的更新器

    • AtomicLongFieldUpdater 原子更新长整型字段的更新器

    • AtomicStampedReference 原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。


    (八).Executor框架(执行机制)

    从JDK5开始,把工作单元和执行机制分离开来,工作单元包括Runnable和Callable,而执行机制由Executor框架提供。

    1.异步计算的结果:FutureTask和Future

    2.任务执行

    (1).Executor(核心接口)

    Executor的生命周期:创建,提交,开始,完成

    (2).ExecutorService接口(继承自Executor)

    • ExecutorService的生命周期:运行,关闭,已终止

    • ExecutorService.shutDown和ExecutorService.shutDownNow的区别

    调用的方法 作用
    shutDown 不再允许新的任务添加到等待队列,正在执行的任务和在等待队列中的任务会执行完毕再关闭。
    shurDownNow 立刻关闭。需要知道正在执行但是还没执行完毕的任务。
    • ExecutorService.submit()和ExecutorService.execute()的区别:接口ExecutorService的execute()方法是继承自Executor。
    调用的方法 作用
    execute 用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。
    submit 用于提交需要返回值的任务。线程池会返回一个Future类型的对象,通过这个Future对象可以判断任务是否执行成功,并且通过Future的get()方法来获取返回值,get()方法会阻塞线程直到任务完成。
    • ExecutorService的创建:
    调用 分类 使用
    Executors.newSingleThreadExecutor() ThreadPoolExecutor 应用场景:适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程活动的应用场景。
    Exectors.newFiexedThreadPool() ThreadPoolExecutor 1.创建一个线程池,具有固定线程数,运行在共享的无界队列中。2.在大多数时候,线程会主动执行任务,当所有的线程都在执行任务时,有新的任务加入进来,就会进入等待队列(可以有源源不断的任务加入进来,因为是无界队列),当有空闲的线程,等待队列中的任务就会被执行。3.如果有线程在执行过程中因为执行失败要关闭,新创建的线程会替失败的线程执行接下来的任务。4.如果想要关闭这个线程池,可以调用ExecutorService的shutDown方法。应用场景:适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。
    Executors.newCachedThreadPool() ThreadPoolExecutor 应用场景:适用于执行很多短期异步任务的小程序,或者是负载较轻的服务器。
    Executors.newScheduledThreadPool() ScheduledThreadPoolExecutor 应用场景:适用于需要多个后台线程执行周期任务,同时为了满足管理的需求而需要限制后台线程的数量的应用场景。
    Executors.newSingleThreadScheduledExecutor() ScheduledThreadPoolExecutor 应用场景:需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务。

    3.任务:Runnable接口和Callable接口


    (九).其他

    1.jstack

    打开cmd,输入:

    • jps 查看pid(进程号)

    • jstack pid

    2.资源限制:指在进行并发编程时,程序的执行速度受到计算机硬件资源或软件资源的限制。

    3.上下文切换

    减少上下文切换的方法:

    • 无锁并发编程

    • CAS算法

    • 使用最少线程

    • 使用协程

    展开全文
  • Java并发编程实战 学习Java推荐书籍 免积分下载 【很抱歉,昨天上传的Java并发编程实战,发现只有部分章节,今天重新上传完整版】
  • Java 并发编程实战-随书源码,下载即可使用。(压缩包附有PDF链接)
  • Java并发编程实战 学习Java推荐书籍 免积分下载 【很抱歉,昨天上传了Java并发编程,刚刚发现该书籍只有部分章节,现在重新上传完全版本的】
  • JAVA并发编程实战

    2019-04-09 09:28:14
    网站 ...> CiCi岛 下载 电子版仅供预览及学习交流使用,...第16届Jolt大奖提名图书 JavaOne大会*畅销图书 了解Java并发编程必读佳作 内容简介 本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。...

    网站

    更多书籍点击进入>> CiCi岛

    下载

    电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍

    封页

    封页

    编辑推荐

    第16届Jolt大奖提名图书   JavaOne大会*畅销图书   了解Java并发编程必读佳作

    内容简介

    本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高并发应用程序的吞吐量,如何识别可并行执行的任务,如何提高单线程子系统的响应性,如何确保并发程序执行预期任务,如何提高并发代码的性能和可伸缩性等内容,最后介绍了一些高级主题,如显式锁、原子变量、非阻塞算法以及如何开发自定义的同步工具类。   本书适合Java程序开发人员阅读。

    作者简介

    本书作者都是Java Community Process JSR 166专家组(并发工具)的主要成员,并在其他很多JCP专家组里任职。Brian Goetz有20多年的软件咨询行业经验,并著有至少75篇关于Java开发的文章。Tim Peierls是“现代多处理器”的典范,他在BoxPop.biz、唱片艺术和戏剧表演方面也颇有研究。Joseph Bowbeer是一个Java ME专家,他对并发编程的兴趣始于Apollo计算机时代。David Holmes是《The Java Programming Language》一书的合著者,任职于Sun公司。Joshua Bloch是Google公司的首席Java架构师,《Effective Java》一书的作者,并参与著作了《Java Puzzlers》。Doug Lea是《Concurrent Programming》一书的作者,纽约州立大学 Oswego分校的计算机科学教授。

    目 录

    对本书的赞誉
    译者序
    前 言
    第1章 简介
     1.1 并发简史
     1.2 线程的优势
      1.2.1 发挥多处理器的强大能力
      1.2.2 建模的简单性
      1.2.3 异步事件的简化处理
      1.2.4 响应更灵敏的用户界面
     1.3 线程带来的风险
      1.3.1 安全性问题
      1.3.2 活跃性问题
      1.3.3 性能问题
     1.4 线程无处不在
    第一部分 基础知识
     第2章 线程安全性
      2.1 什么是线程安全性
      2.2 原子性
       2.2.1 竞态条件
       2.2.2 示例:延迟初始化中的竞态条件
       2.2.3 复合操作
      2.3 加锁机制
       2.3.1 内置锁
       2.3.2 重入
      2.4 用锁来保护状态
      2.5 活跃性与性能
     第3章 对象的共享
      3.1 可见性
       3.1.1 失效数据
       3.1.2 非原子的64位操作
       3.1.3 加锁与可见性
       3.1.4 Volatile变量
      3.2 发布与逸出
      3.3 线程封闭
       3.3.1 Ad-hoc线程封闭
       3.3.2 栈封闭
       3.3.3 ThreadLocal类
      3.4 不变性
       3.4.1 Final域
       3.4.2 示例:使用Volatile类型来发布不可变对象
      3.5 安全发布
       3.5.1 不正确的发布:正确的对象被破坏
       3.5.2  不可变对象与初始化安全性
       3.5.3 安全发布的常用模式
       3.5.4 事实不可变对象
       3.5.5 可变对象
       3.5.6 安全地共享对象
     第4章 对象的组合
      4.1 设计线程安全的类
       4.1.1 收集同步需求
       4.1.2 依赖状态的操作
       4.1.3 状态的所有权
      4.2 实例封闭
       4.2.1 Java监视器模式
       4.2.2 示例:车辆追踪
      4.3 线程安全性的委托
       4.3.1 示例:基于委托的车辆追踪器
       4.3.2 独立的状态变量
       4.3.3 当委托失效时
       4.3.4 发布底层的状态变量
       4.3.5 示例:发布状态的车辆追踪器
      4.4 在现有的线程安全类中添加功能
       4.4.1 客户端加锁机制
       4.4.2 组合
      4.5 将同步策略文档化
     第5章 基础构建模块
      5.1 同步容器类
       5.1.1 同步容器类的问题
       5.1.2 迭代器与Concurrent-ModificationException
       5.1.3 隐藏迭代器
      5.2 并发容器
       5.2.1 ConcurrentHashMap
       5.2.2 额外的原子Map操作
       5.2.3 CopyOnWriteArrayList
      5.3 阻塞队列和生产者-消费者模式
       5.3.1 示例:桌面搜索
       5.3.2 串行线程封闭
       5.3.3 双端队列与工作密取
      5.4 阻塞方法与中断方法
      5.5 同步工具类
       5.5.1 闭锁
       5.5.2 FutureTask
       5.5.3 信号量
       5.5.4 栅栏
      5.6 构建高效且可伸缩的结果缓存
    第二部分 结构化并发应用程序
     第6章 任务执行
      6.1 在线程中执行任务
       6.1.1 串行地执行任务
       6.1.2 显式地为任务创建线程
       6.1.3 无限制创建线程的不足
      6.2 Executor框架
       6.2.1 示例:基于Executor的Web服务器
       6.2.2 执行策略
       6.2.3 线程池
       6.2.4 Executor的生命周期
       6.2.5 延迟任务与周期任务
      6.3 找出可利用的并行性
       6.3.1 示例:串行的页面渲染器
       6.3.2 携带结果的任务Callable与Future
       6.3.3 示例:使用Future实现页面渲染器
       6.3.4 在异构任务并行化中存在的局限
       6.3.5 CompletionService:Executor与BlockingQueue
       6.3.6 示例:使用CompletionService实现页面渲染器
       6.3.7 为任务设置时限
       6.3.8 示例:旅行预定门户网站
     第7章 取消与关闭
      7.1 任务取消
       7.1.1 中断
       7.1.2 中断策略
       7.1.3 响应中断
       7.1.4 示例:计时运行
       7.1.5 通过Future来实现取消
       7.1.6 处理不可中断的阻塞
       7.1.7 采用newTaskFor来封装非标准的取消
      7.2 停止基于线程的服务
       7.2.1 示例:日志服务
       7.2.2 关闭ExecutorService
       7.2.3 “毒丸”对象
       7.2.4 示例:只执行一次的服务
       7.2.5 shutdownNow的局限性
      7.3 处理非正常的线程终止
      7.4 JVM关闭
       7.4.1 关闭钩子
       7.4.2 守护线程
       7.4.3 终结器
     第8章 线程池的使用
      8.1 在任务与执行策略之间的隐性耦合
       8.1.1 线程饥饿死锁
       8.1.2 运行时间较长的任务
      8.2 设置线程池的大小
      8.3 配置ThreadPoolExecutor
       8.3.1 线程的创建与销毁
       8.3.2 管理队列任务
       8.3.3 饱和策略
       8.3.4 线程工厂
       8.3.5 在调用构造函数后再定制ThreadPoolExecutor
      8.4 扩展 ThreadPoolExecutor
      8.5 递归算法的并行化
     第9章 图形用户界面应用程序
      9.1 为什么GUI是单线程的
       9.1.1 串行事件处理
       9.1.2 Swing中的线程封闭机制
      9.2 短时间的GUI任务
      9.3 长时间的GUI任务
       9.3.1 取消
       9.3.2 进度标识和完成标识
       9.3.3 SwingWorker
      9.4 共享数据模型
       9.4.1 线程安全的数据模型
       9.4.2 分解数据模型
       9.5 其他形式的单线程子系统
    第三部分 活跃性、性能与测试
     第10章 避免活跃性危险
      10.1 死锁
       10.1.1 锁顺序死锁
       10.1.2 动态的锁顺序死锁
       10.1.3 在协作对象之间发生的死锁
       10.1.4 开放调用
       10.1.5 资源死锁
      10.2 死锁的避免与诊断
       10.2.1 支持定时的锁
       10.2.2 通过线程转储信息来分析死锁
      10.3 其他活跃性危险
       10.3.1 饥饿
       10.3.2 糟糕的响应性
       10.3.3 活锁
     第11章 性能与可伸缩性
      11.1 对性能的思考
       11.1.1 性能与可伸缩性
       11.1.2 评估各种性能权衡因素
      11.2 Amdahl定律
       11.2.1 示例:在各种框架中隐藏的串行部分
       11.2.2 Amdahl定律的应用
      11.3 线程引入的开销
       11.3.1 上下文切换
       11.3.2 内存同步
       11.3.3 阻塞
      11.4 减少锁的竞争
       11.4.1 缩小锁的范围(“快进快出”)
       11.4.2 减小锁的粒度
       11.4.3 锁分段
       11.4.4 避免热点域
       11.4.5 一些替代独占锁的方法
       11.4.6 监测CPU的利用率
       11.4.7 向对象池说“不”
      11.5 示例:比较Map的性能
      11.6 减少上下文切换的开销
     第12章 并发程序的测试
      12.1 正确性测试
       12.1.1 基本的单元测试
       12.1.2 对阻塞操作的测试
       12.1.3 安全性测试
       12.1.4 资源管理的测试
       12.1.5 使用回调
       12.1.6 产生更多的交替操作
      12.2 性能测试
       12.2.1 在PutTakeTest中增加计时功能
       12.2.2 多种算法的比较
       12.2.3 响应性衡量
      12.3 避免性能测试的陷阱
       12.3.1 垃圾回收
       12.3.2 动态编译
       12.3.3 对代码路径的不真实采样
       12.3.4 不真实的竞争程度
       12.3.5 无用代码的消除
      12.4 其他的测试方法
       12.4.1 代码审查
       12.4.2 静态分析工具
       12.4.3 面向方面的测试技术
       12.4.4 分析与监测工具
    第四部分 高级主题
     第13章 显式锁
      13.1 Lock与 ReentrantLock
       13.1.1 轮询锁与定时锁
       13.1.2 可中断的锁获取操作
       13.1.3 非块结构的加锁
      13.2 性能考虑因素
      13.3 公平性
      13.4 在synchronized和ReentrantLock之间进行选择
      13.5 读-写锁
     第14章 构建自定义的同步工具
      14.1 状态依赖性的管理
       14.1.1 示例:将前提条件的失败传递给调用者
       14.1.2 示例:通过轮询与休眠来实现简单的阻塞
       14.1.3 条件队列
      14.2 使用条件队列
       14.2.1 条件谓词
       14.2.2 过早唤醒
       14.2.3 丢失的信号
       14.2.4 通知
       14.2.5 示例:阀门类
       14.2.6 子类的安全问题
       14.2.7 封装条件队列
       14.2.8 入口协议与出口协议
      14.3 显式的Condition对象
      14.4 Synchronizer剖析
      14.5 AbstractQueuedSynchronizer
      14.6 java.util.concurrent同步器类中的 AQS
       14.6.1 ReentrantLock
       14.6.2 Semaphore与CountDownLatch
       14.6.3 FutureTask
       14.6.4 ReentrantReadWriteLock
     第15章 原子变量与非阻塞同步机制
      15.1 锁的劣势
      15.2 硬件对并发的支持
       15.2.1 比较并交换
       15.2.2 非阻塞的计数器
       15.2.3 JVM对CAS的支持
      15.3 原子变量类
       15.3.1 原子变量是一种“更好的volatile”
       15.3.2 性能比较:锁与原子变量
      15.4 非阻塞算法
       15.4.1 非阻塞的栈
       15.4.2 非阻塞的链表
       15.4.3 原子的域更新器
       15.4.4 ABA问题
     第16章 Java内存模型
      16.1 什么是内存模型,为什么需要它
       16.1.1 平台的内存模型
       16.1.2 重排序
       16.1.3 Java内存模型简介
       16.1.4 借助同步
      16.2 发布
       16.2.1 不安全的发布
       16.2.2 安全的发布
       16.2.3 安全初始化模式
       16.2.4 双重检查加锁
      16.3 初始化过程中的安全性
    附录A 并发性标注
    参考文献

    前 言

      在写作本书时,对于中端桌面系统来说,多核处理器正变得越来越便宜。无独有偶,许多开发团队也注意到,在他们的项目中出现了越来越多与线程有关的错误报告。在NetBeans开发者网站上的最近一次公告中,一位核心维护人员注意到,为了修复与线程相关的问题,在某个类中竟然打了14次补丁。Dion Almaer,这位TheServerSide网站的前编辑,最近(在经过一番痛苦的调试过程并最终发现了一个与线程有关的错误之后)在其博客上写道,在大多数Java程序中充满了各种并发错误,使得程序只有在“偶然的情况下”才能正常工作。

    确实,在开发、测试以及调试多线程程序时存在着巨大的困难,因为并发性错误通常并不会以某种确定的方式显现出来。当这些错误出现时,通常是在最糟糕的时刻,例如在正式产品中,或者在高负载的情况下。

    当开发Java并发程序时,所要面对的挑战之一就是:平台提供的各种并发功能与开发人员在程序中需要的并发语义并不匹配。在Java语言中提供了一些底层机制,例如同步和条件等待,但在使用这些机制来实现应用级的协议与策略时必须始终保持一致。如果没有这些策略,那么在编写程序时,虽然程序看似能顺利地编译和运行,但却总会出现各种奇怪的问题。许多介绍并发的其他书籍更侧重于介绍一些底层机制和API,而在设计级的策略和模式上叙述的不多。

    Java
    5.0在Java并发应用程序的开发方面进展巨大,它不仅提供了一些新的高层组件,还补充了一些底层机制,从而使得无论是新手级开发人员还是专家级开发人员都能够更容易地构建并发应用程序。本书的作者都是JCP专家组的主要成员,也正是该专家组编写了这些新功能。本书不仅描述了这些新功能的行为和特性,还介绍了它们的底层设计模式和促使它们被添加到平台库中的应用场景。

    我们的目标是向读者介绍一些设计规则和思维模式,从而使读者能够更容易也更乐意去构建正确的以及高性能的Java并发类和应用程序。

    我们希望你能享受本书的阅读过程。

    Brian Goetz  

    Williston,VT  

    2006年3月

    如何使用本书

    为了解决在Java底层机制与设计级策略之间的不匹配问题,我们给出了一组简化的并发程序编写规则。专家看到这些规则会说:“嗯,这并不是完整的规则集。即使类C违背了规则R,它仍然是线程安全的。”虽然在违背一些规则的情况下仍有可能编写出正确的并发程序,但这需要对Java内存模型的底层细节有着深入的理解,而我们希望开发人员无须掌握这些细节就能编写出正确的并发程序。只要始终遵循这组简单的规则,就能编写出正确的并且可维护的并发程序。

    我们假设读者对Java的基本并发机制已经有了一定程度的了解。本书并非是对并发的入门介绍—要了解这方面的内容,请参考其他书籍中有关线程的内容,例如《The
    Java Programming
    Language》(Arnold等,2005)。此外,本书也不是介绍并发的百科全书—要了解这方面的内容,请参考《Concurrent
    Programming in
    Java》(Lea,2000)。事实上,本书提供了各种实用的设计规则,用于帮助开发人员创建安全的和高性能的并发类。在本书中相应的地方引用了以下书籍中的相关章节:《The
    Java Programming Language》、《Concurrent Programming in Java》、《The
    Java Language Specification》 ( Gosling等,2005 )以及《Effective Java
    》(Bloch, 2001),并分别使用[JPL n.m]、[CPJ n.m]、[JLS n.m]和[EJ Item
    n]来表示它们。

    在进行简要的介绍(第1章)之后,本书共分为四个部分:

    基础知识。第一部分(第2章~第5章)重点介绍了并发性和线程安全性的基本概念,以及如何使用类库提供的基本并发构建块来构建线程安全类。在第一部分给出了一个清单,其中总结了这一部分中介绍的最重要的规则。

    第2章与第3章构成了本书的基础。在这两章中给出了几乎所有用于避免并发危险、构造线程安全的类以及验证线程安全的规则。如果读者重“实践”而轻“理论”,那么可能会直接跳到第二部分,但在开始编写任何并发代码之前,一定要回来读一读这两章!

    第4章介绍了如何将一些小的线程安全类组合成更大的线程安全类。第5章介绍了在平台库中提供的一些基础的并发构建模块,包括线程安全的容器类和同步工具类。

    结构化并发应用程序。第二部分(第6章~第9章)介绍了如何利用线程来提高并发应用程序的吞吐量或响应性。第6章介绍了如何识别可并行执行的任务,以及如何在任务执行框架中执行它们。第7章介绍了如何使任务和线程在执行完正常工作之前提前结束。在健壮的并发应用程序与看似能正常工作的应用程序之间存在的重要差异之一就是,如何实现取消以及关闭等操作。第8章介绍了任务执行框架中的一些更高级特性。第9章介绍了如何提高单线程子系统的响应性。

    活跃性、性能与测试。第三部分(第10章~第12章)介绍了如何确保并发程序执行预期的任务,以及如何获得理想的性能。第10章介绍了如何避免一些使程序无法执行下去的活跃性故障。第11章介绍了如何提高并发代码的性能和可伸缩性。第12章介绍了在测试并发代码的正确性和性能时可以采用的一些技术。

    高级主题。第四部分(第13章~第16章)介绍了资深开发人员可能感兴趣的一些主题,包括:显式锁、原子变量、非阻塞算法以及如何开发自定义的同步工具类。

    代码示例

    虽然书中很多一般性的概念同样适用于Java
    5.0之前的版本以及一些非Java的运行环境,但其中大多数示例代码(以及关于Java内存模型的所有描述)是基于Java
    5.0或更高版本的,而且某些代码示例中还使用了Java 6的一些新增功能。

    我们对书中的代码示例已经进行了压缩,以便减少代码量并重点突出与内容相关的部分。在本书的网站http://www.javaconcurrencyinpractice.com上提供了完整的代码示例、辅助示例以及勘误表。

    代码示例可分为三类:“好的”示例、“一般的”示例和“糟糕的”示例。“好的”示例是应该被效仿的技术。“糟糕的”示例是一定不能效仿的技术,而且还会用一个“Mr.
    Yuk”的图标来表示该示例中的代码是“有害的”(参见程序清单1)。“一般的”示例给出的技术并不一定是错的,但却是脆弱的、有风险的或是性能较差的,并且会用一个“Mr.Could
    Be Happier”图标来表示,如程序清单2所示。

    程序清单1 糟糕的链表排序方式(不要这样做)

    public > void sort(List list) {

    // 永远不要返回错误的答案!

    System.exit(0);

    }

    有些读者会质疑这些“糟糕的”示例在本书中的作用,毕竟,在一本书中应该给出如何做正确的事,而不是错误的事。这些“糟糕的”示例有两个目的,它们揭示了一些常见的缺陷,但更重要的是它们示范了如何分析程序的线程安全性,而要实现这个目的,最佳的方式就是观察线程安全性是如何被破坏的。

    程序清单2 非最优方式的链表排序

    public > void sort(List list) {

    for (int i=0; i<1000000; i++)

    doNothing();

    Collections.sort(list);

    }

      致谢

    本书诞生于Java Community Process JSR 166 为Java
    5.0开发java.util.concurrent包的过程中。还有许多人参与到JSR 166中,特别感谢Martin
    Buchholz将全部的工作融入到JDK中,并感谢concurrency-interest邮件列表中的所有读者对API草案提出的建议和反馈。

    有不少来自各方面的人员都提出了建议和帮助,使得本书的内容得到了极大的充实。感谢Dion
    Almaer、Tracy Bialik、Cindy Bloch、Martin Buchholz、Paul
    Christmann、Cliff Click、Stuart Halloway、David Hovemeyer、Jason
    Hunter、Michael Hunter、Jeremy Hylton、Heinz Kabutz、Robert
    Kuhar、Ramnivas Laddad、Jared Levy、Nicole Lewis、Victor
    Luchangco、Jeremy Manson、Paul Martin、Berna Massingill、Michael
    Maurer、Ted Neward、Kirk Pepperdine、Bill Pugh、Sam Pullara、Russ
    Rufer、Bill Scherer、Jeffrey Siegal、Bruce Tate、Gil Tene、Paul
    Tyma,以及硅谷模式小组的所有成员,他们通过各种技术交流为本书提供了指导建议,使得本书更加完善。

    特别感谢Cliff Biffle、Barry Hayes、Dawid
    Kurzyniec、Angelika Langer、Doron Rajwan和Bill
    Venners,他们非常仔细地审阅了本书的全稿,指出了代码示例中的错误,并提出了大量的改进建议。

    感谢Katrina Avery的编辑工作,以及Rosemary
    Simpson在非常短的时间里完成了索引生成工作。感谢Ami Dewar绘制的插图。

    感谢Addison-Wesley的全体成员,他们使本书得以最终问世。Ann
    Sellers启动了编写本书的项目,Greg Doench监督并帮助本书有条不紊地完成,Elizabeth
    Ryan负责本书的出版过程。

    此外还要感谢许许多多的软件工程师,他们开发了本书得以依赖的各种软件,这些软件包括TEX、LATEX、Adobe
    Acrobat、pic、grap、Adobe Illustrator、Perl、Apache Ant、IntelliJ
    IDEA、GNU emacs、Subversion、TortoiseSVN,当然,还有Java平台及其类库。

    媒体评论

      “我曾有幸在一个伟大的团队中工作,参与设计和实现在Java 5.0和Java 6等平台中新增的并发功能。现在,仍然是这个团队,将透彻地讲解这些新功能,以及关于并发的一般性概念。并发已不再只是高级用户谈论的话题,每一位Java开发人员都应该阅读这本书。” —Martin Buchholz,Sun公司的JDK并发大师  

    “在过去30多年时间里,计算机性能一直遵循着摩尔定律,但从现在开始,它将遵循Amdahl定律。编写能高效利用多处理器的代码非常具有挑战性。在这本书中介绍的一些概念和技术,对于在当前(以及未来的)系统上编写安全的和可伸缩的代码来说都是非常有用的。”—Doron
    Rajwan,Intel公司研究人员  

    “如果你正在编写、设计、调试、维护以及分析多线程的Java程序,那么本书正是你所需要的。如果你曾对某个方法进行过同步,但却不理解其中的原因,那么你以及你的用户都有必要从头至尾仔细地读一读这本书。”
    —Ted Neward,《Effective Enterprise Java》的作者  

    “Brian非常清晰地阐述了并发的一些基本问题与复杂性。对于使用线程并关注程序执行性能的开发人员来说,这是一本必读的书。” —Kirk
    Pepperdine,JavaPerformanceTuning.com网站CTO  

    “本书深入浅出地介绍了一些复杂的编程主题,是一本完美的Java并发参考手册。书中的每一页都包含了程序员日常需要应对的问题(以及相应的解决方案)。随着摩尔定律的发展趋势由提高处理器核的速度转向增加处理器核的数量,如何有效地利用并发性已变得越来越重要,本书正好介绍了这些方面的内容。”
    —Cliff Click博士,Azul Systems公司高级软件工程师  

    “我对并发有着浓厚的兴趣,并且与大多数程序员相比,我或许写过更多存在线程死锁的代码,也在同步上犯了更多的错误。在介绍Java线程和并发等主题的众多书籍中,Brian的这本书*可读性,它通过循序渐进的方式将一些复杂的主题阐述得很清楚。我将本书推荐给Java
    Specialists?Newsletter的所有读者,因为它不仅有趣,而且很有用,它介绍了当前Java开发人员正在面对的许多问题。”
    —Heinz Kabutz博士,Java Specialists?Newsletter的维护者  

    “我一直努力想使一些简单的问题变得更简单,然而本书已经简化了一个复杂但却关键的主题:并发。这本书采用了创新的讲解方法、简单明了的风格,它注定会成为一本非常重要的书。
    —Bruce Tate,《Beyond Java》的作者  

    这本书为Java开发人员在线程编程领域提供了不可多得的知识。我在读这本书时受到了极大的启发,部分原因在于它详细地介绍了Java中并发领域的API,但更重要的却在于这本书以一种透彻并且易懂的方式来介绍复杂的并发知识,这是其他书籍很难媲美的。
    —Bill Venners,《Inside the Java Virtual Machine》的作者

    展开全文
  • Java并发编程实战》的高清完整PDF版,需要学习Java并发编程的同学,可以下载学习
  • java并发编程是一本关于java多线程 与锁的相关知识的书 要实现java并发编程的 程序员可下载观看
  • Java并发编程实战

    2014-07-31 12:16:28
    把这个文档共享给大家,下载收藏,这是一本好书啊,电子版的随时随地都可以阅读
  • 学习的是2012版的《Java并发编程实战》,找了半天网上只有不带书签的pdf版,而CSDN下载也因为版权问题不允许上传和下载这本书,于是自己用acrobat给这本书添加了书签,在这里放上百度云链接,有需自取,链接无效可以...

    又挖了一个待更新的坑。。。 

    书籍链接

    学习的是2012版的《Java并发编程实战》,找了半天网上只有不带书签的pdf版,而CSDN下载也因为版权问题不允许上传和下载这本书,于是自己用acrobat给这本书添加了书签,在这里放上百度云链接,有需自取,链接无效可以评论邮件发。

    链接:https://pan.baidu.com/s/16Y56Yej5LvbSMRMhVfuH_w 
    提取码:zokm

    补充

    因为原书的说明很详细,在这里只放一些原书中觉得必要的概念,和自己的一些思考,或者补充知识,也是方便日后复习时快速回顾。

    第一章 简介

    线程也被称为轻量级进程。在大多数现代操作系统中,都是以线程为基本的调度单位,而不是进程。

    同一个进程中的所有线程都将共享进程的内存地址空间,即它们访问相同的变量并在同一个堆上分配对象。

    由于基本的调度单位是线程,因此如果在程序中只有一个线程,那么最多同时只能在一个处理器上运行。

    相比于单线程程序,多线程程序中,管理不同任务间的优先级和执行时间,并在任务之间进行切换将带来额外的开销。

    以下的模块都将在应用程序之外的线程中调用应用程序的代码

    Timer。Timer类的作用是使任务再稍后的时刻运行,或者运行一次,或者周期性地运行。TimerTask将在Timer管理的线程中执行,而不是由应用程序来管理。如果某个TimerTask访问了应用程序中其他线程访问的数据,那么不仅TimerTask需要以线程安全的方式来访问数据,其他类也必须采用线程安全的方式来访问该数据。因此引入Timer可能会使串行程序变得复杂。最简单实现这个目标的方式是确保TimerTask访问的对象本身是线程安全的,从而就能把线程安全性封装在共享对象内部。

    Servlet和JavaServer Page(JSP)。Servlet框架用于部署网页应用程序以及分发来自HTTP客户端的请求。到达服务器的请求可能会通过一个过滤器链被分发到正确的Servlet或JSP。每个Servlet都表示一个程序逻辑组件,在高吞吐率的网站中,多个客户端可能同时请求同一个Servlet的服务。在Servlet规范中,Servlet同样需要满足被多个线程同时调用,换句话说,Servlet需要是线程安全的。即使你可以确保每次只有一个线程调用某个Servlet,但在构建网页应用程序时仍然必须注意线程安全性。Servlet通常会访问与其他Servlet共享的信息,例如应用程序中的对象(这些对象保存在ServletContext中)或者会话中的对象(这些对象保存在每个客户端的HttpSession中)。当一个Servlet访问在多个Servlet或者请求中共享的对象时,必须正确地协同对这些对象的访问,因为多个请求可能在不同的线程中同时访问这些对象。Servlet和JSP,以及在ServletContext和HttpSession等容器中保存的Servlet过滤器和对象等,都必须是线程安全的。

    远程方法调用(Remote Method Invocation,RMI)。RMI使代码能够调用在其他JVM中运行的对象。当通过RMI调用某个远程方法时,传递给方法的参数必须被打包(也称为列集[Marshaled])到一个字节流中,通过网络传输给远程JVM,然后由远程JVM拆包(或者称为散集[Unmarshaled])并传递给远程方法。当RMI代码调用远程对象时,这个调用将在一个由RMI管理的线程中调用对象。远程对象必须注意两个线程安全性问题:正确地协同在多个对象中共享的状态,以及对远程对象本身状态的访问(由于同一个对象可能会在多个线程中被同时访问)。与Servlet相同,RMI对象应该做好被多个线程同时调用的准备,并且必须确保它们自身的线程安全性。

    Swing和AWT。GUI应用程序的一个固有属性是异步性。用户可以在任意时刻选择一个菜单项或者按下一个按钮,应用程序就会及时响应,即使应用程序当时正在执行其他的任务。Swing和AWT创建了一个单独的线程来处理用户触发的事件,并对呈现给用户的图形界面进行更新。Swing的一些组件并不是线程安全的,例如JTable。相反,Swing程序通过将所有对GUI组件的访问局限在事件线程中以实现线程安全性。如果某个应用程序希望在事件线程之外控制GUI,那么必须将控制GUI的代码放在事件线程中运行。当用户触发某个UI动作时,在事件线程中就会有一个事件处理器被调用以执行用户请求的操作。如果事件处理器需要访问由其他线程同时访问的应用程序状态(例如编辑某个文档),那么这个事件处理器,以及访问这个状态的所有其他代码,都必须采用一种线程安全的方式来访问该状态。

    展开全文
  • 1,在程序开发中我们经常会对异构的任务进行并行化处理,例如一个线程负责数据下载,另一个线程响应ui操作 2,但是有时候多个异构的任务并行并不能保证程序的效率,例如数据下载需要1秒,数据计算需要10秒,那么将这...

    构建高效的并行计算

    1,在程序开发中我们经常会对异构的任务进行并行化处理,例如一个线程负责数据下载,另一个线程响应ui操作

    2,但是有时候多个异构的任务并行并不能保证程序的效率,例如数据下载需要1秒,数据计算需要10秒,那么将这两个任务并行处理也只能提高9%的效率

    3,只有当大量相互独立且同构的任务可以并行处理时,才能体现出将程序的工作负载分配到多个任务中带来的真正性能提升

    示例代码如下

    public abstract class ComputeSample<IN, OUT, DATA> {
    	/**
    	 * 可缓存的线程池,
    	 * 如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,
    	 * 当需求增加是,则可以添加性的线程,
    	 * 线程池的规模不存在任何的限制
    	 */
    	private final ExecutorService executor = Executors.newCachedThreadPool();
    	
    	public void compute(IN param) {
    		final List<DATA> datas = scanForData(param);
    		// 通过executor管理线程池,
    		// 通过submit提交任务Callable,
    		// 通过BlockingQueue管理计算完成的结果
    		CompletionService<OUT> completionService =
                    new ExecutorCompletionService<OUT>(executor);
    		for (final DATA data : datas){
                completionService.submit(new Callable<OUT>() {
                    public OUT call() {
                        return doCompute(data);
                    }
                });
    		}
    		
    		try {
                for (int t = 0, n = datas.size(); t < n; t++) {
                    // take和poll方法是委托给了BlockingQueue的
                	Future<OUT> f = completionService.take();
                	// 获得各个计算结果
                    OUT imageData = f.get();
                    doSomething(imageData);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                throw launderThrowable(e.getCause());
            }
    	}
    	
    	// 构建计算参数
    	abstract List<DATA> scanForData(IN param);
    	
    	// 耗时的计算过程
    	abstract OUT doCompute(DATA param);
    	
    	// 计算结果处理
    	abstract void doSomething(OUT param);
    }
    


    展开全文
  • 下载地址 链接:https://pan.baidu.com/s/1i6FlscH 密码:m21n 1.任务执行 任务是一组逻辑执行单元,线程是使得任务异步执行的机制 不可取的所谓线程开启的方式: 1.所有任务放在单个线程中串行执行 2.每一个任务...
  • Java7并发编程实战手册》书中实例代码,有此书的TX就直接在此下载吧。
  • java并发编程源码

    2018-02-22 11:54:01
    java并发编程实战源码。可以下载的书中的源码及实例。
  • │ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
  • 发布订阅:生产者生产消息到队列,消费者去队列订阅。 应用场景: 1.高速对低速 ...--------------------------不实现了,自己研究源码-------下载源码的地址可以复习下----------------------- ...
  • 本文将自己所搜集的几本java及相关的计算机电子版书籍分享出来,以便为各位下载。 已经检查过链接的有效性,不保证...Java并发编程实战 人月神话 点我合集下载 (电子版仅供预览及学习交流使用,下载后请24小时...
  • Java并发编程的艺术

    2020-09-06 15:56:17
    Java并发编程的艺术 下载地址 https://pan.baidu.com/s/1rIWyFEndQliXdp8swqtHqw 扫码下面二维码关注公众号回复 100060获取分享码 本书目录结构如下: 第1章并发编程的挑战1 1.1上下文切换1 1.1.1多线程...
  • 第1章并发编程的挑战1 1.1上下文切换1 1.1.1多线程一定快吗1 1.1.2测试上下文切换次数和时长3 1.1.3如何减少上下文切换3 1.1.4减少上下文切换实战4 1.2死锁5 1.3资源限制的挑战6 1.4本章小结7 第2
  • 第1章 课程开篇 第2章 并发编程框架中心讲解 ...第6章 Netty整合并发编程框架Disruptor实战百万长链接服务构建 第7章 分布式一致ID生成效劳架构规划 第8章 课程总结 coding.rar下载地址:百度网盘 ...
  • 如果你是已经入门Java的,那么这一套资料能让你更加深入的了解Java 或是 编程的魅力了,高并发 这个关键词都不陌生 ,但是你真的了解吗? 其中还包括 数据结构 与 算法 ...期待您下载阅读...
  • 实战java高并发程序设计,学习java并发编程的一手资料,值得一看。在过去单核CPU时代,单任务在一个时间点只能执行单一程序,随着多核CPU的发展,并行程序开发就显得尤为重要。, 《实战Java高并发程序设计》主要介绍...
  • Java并发

    2018-05-27 19:23:12
    声明:Java并发的内容是自己阅读《Java并发编程实战》和《Java并发编程的艺术》整理来的。 个人网站 图文并茂请戳 思维导图下载请戳 目录 (1)基础概念 (2)线程 (3)锁 (4)同步器 (5)并发容器和框架 (6)Java并发工具...
  • Java架构师高级课/微服务/高并发/高性能/性能调优/电商缓存/并发编程/虚拟机/大型分布式电商项目实战视频下载 39套Java架构师,高级课,微服务,微信支付宝支付,公众号开发,java8新特性,P2P金融项目,程序设计,...
  • │ ├─Java并发编程.png │ ├─源码+ppt.rar │ ├─高并发编程第一阶段01讲、课程大纲及主要内容介绍.wmv │ ├─高并发编程第一阶段02讲、简单介绍什么是线程.wmv │ ├─高并发编程第一阶段03讲、创建并...
  • │ ├─Java并发编程.png  │ ├─源码+ppt.rar │ ├─高并发编程第一阶段01讲、课程大纲及主要内容介绍.wmv │ ├─高并发编程第一阶段02讲、简单介绍什么是线程.wmv │ ├─高并发编程第一阶段03讲、创建并启动...
  • 主要涉及Scala的函数式风格、自适应类型、闭包、XML处理、模式匹配和并发编程等内容。通过学习本书,你可以使用Scala的强大能力,创建多线程的应用程序。 这本书是为想了解Scala的程序员和有经验的Java程序员准备的...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 228
精华内容 91
关键字:

java并发编程实战下载

java 订阅