[注] 同步机制保证:1)原子性 2)内存可见性;

  Volatile变量只能保证:1)可见性; - 恰当的同步,同步的弱形式,确保对一个变量的更新以可预见的方式告知其他线程。

 

[注] 用锁来协调访问变量时,每次访问变量都需要用同一个锁。锁不仅仅是关于同步与互斥的,也是关于内存可见的。

  为了保证所有线程都能够看到共享的、可变变量的最新值,读取和写入线程必须使用公共的锁进行同步。

 

[注] Java提供的内部锁是可重进入的,因为线程在试图获取它自己占有的锁时,请求会成功。重进入(Reenter)意味着锁的请求是基于"每线程",而不是基于"每调用";

 

[注] **本地(基于栈的)变量,不会被跨线程共享,因此不需要同步;

    每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,栈内存可以理解为线程的私有内存;

 

[注] 线程中断是一个协作机制,每一个线程都有一个boolean类型的中断状态,在中断的时候,这个中断状态被设置为true。

  阻塞库函数,比如:Thread.sleep()和Object.wait(),试图监测线程何时被中断,它们对中断的响应表现为:清除中断状态,抛出InterruptedException,这表示阻塞操作因为中断而提前结束。

 

[注] Volatile变量 vs 锁

  Volatile变量与锁相比是更轻量的同步机制,它们不会引起上下文的切换和线程调度。然而,Volatile变量与锁相比有一些局限性:

  尽管它们提供了相似的可见性保证,但是它们不能用于构建原子化的复合操作。这意味着当一个变量依赖其他变量时,或者当前变量的新值依赖于旧值时,是不能用Volatile变量的。

[注] 原子变量类 vs 锁

  原子变量比锁更精巧,更轻量,因为它不会引起线程的挂起和重新调度;

  CAS:compare and set; 非阻塞算法;

    术语:检查并运行

[注] 条件队列

  Object中的wait、notify、notifyAll方法构成了内部条件队列的API

  一个对象的内部锁与它的内部条件队列是相关的,为了能够调用对象X的任一个条件队列方法,必须持有对象的锁;

  条件谓语涉及状态变量,状态变量是由锁保护的,所以测试条件谓语之前,必须先持有锁;

  * 锁、条件谓语和条件变量之间的三元关系,涉及条件谓词的变量必须由锁保护,检查条件谓词时以及调用wait和notify时,必须持有锁对象;

  状态依赖方法的规范式:

void stateDependentMethod() throws InterruptedException{
		//条件谓语必须被锁守护
		synchronized(lock){
			while(!conditionPredicate()){
				lock.wait();
			}
			//现在,对象处于期望的状态中
		}
	}

  Obejct.wait 内部流程:

    1) 会自动释放锁,并请求OS挂起当前线程,让其他线程可以获得该锁进而修改对象的状态;

    2) 线程被唤醒时,wait会重新请求与条件队列相关联的锁;

  Object.notify:JVM从条件队列中等待的众多线程中挑选出一个并把它唤醒;

  Object.notifyAll:JVM唤醒条件队列中等待的所有线程;(通常使用notifyAll)

[注] 一个公平的条件队列可以确保线程从等待集中释放的相对顺序,内部条件队列并不提供公平队列,显式的Condition可以提供公平/非公平队列的选择;

 

[注] Condition是显式的条件队列(await、signal、signalAll等方法),一个Condition与一个单独的Lock相关联,Lock.newCondition()可以创建一个Condition;

[注] Lock:显式锁,可中断的锁获取请求,中断将抛出InterruptedException;

public boolean sendOnShareLine(String message) throws InterruptedException{
		lock.lockInterruptibly();
		try{
			return cancellableSendOnSharedLine(message);
		}finally{
			lock.unlock();
		}
	}
	
	private boolean cancellableSendOnSharedLine(String message)
		throws InterruptedException{ ... }

  

  阻塞队列 BlockingQueue : LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue
    1)阻塞方法:put()、take()
    2)非阻塞方法:offer()、poll()


  Executor框架 - 任务执行框架:将任务的提交与任务的执行体进行解耦,可以简单的为给定的任务制定执行策略。

    类库提供了一个灵活的线程池实现:ThreadPoolExecutor,以及一些有用的预设配置,可以通过 Executors 中的静态工厂方法创建一个线程池:

    newFixedThreadPool

    newCachedThreadPool

    newScheduledThreadPool

    newSingleThreadExecutor

  为了解决执行服务的生命周期问题,ExecutorService 接口扩展了Executor,添加了一些用于生命周期管理的方法,同时还有一些用于任务提交的便利方法。

  想要使用Executor,还必须能够将任务描述为Runnable。Executor框架使用Runnable作为其任务的基本表达形式。

    - Runnable 只是相当有限的抽象,run方法不能返回值或者抛出受检查的异常;

    - Callable 可携带结果的任务,可以把其他类型的任务封装成一个Callable;

  一个Executor执行的任务的生命周期有4个阶段:创建、提交、开始和完成。

  Future 用以描述"任务"的生命周期,提供方法来获得任务的结果、取消任务以及检查任务是否已经完成还是被取消。

  有很多种方法可以创建一个描述任务的Future:

 - 将一个Runnable或一个Callable提交给executor,然后得到一个描述任务执行的Future,如:ExecutorService.submit()方法;

    - 显示为给定的Runnable或Callable实例化一个FutureTask

  

public interface Callable<V>{
		V call() throws Exception;
	}
	
	public interface Future<V>{
		boolean cancel(boolean mayInterruptIfRunning);
		boolean isCancelled();
		boolean isDone();
		V get() throws InterruptedException,ExecutionException,CancellationException;
		V get(long timeout,TimeUnit unit) 
			throws InterruptedException,ExecutionException,CancellationException,TimeoutException;
	}