

注意:1,在使用synchronized块来同步方法时,非静态方法可以通过this来同步,而静态方法必须使用class对象来同步,但是非静态方法也可以通过使用class来同步静态方法。但是静态方法中不能使用this来同步非静态方法。这点在使用synchronized块需要注意。
2,所以一个对象内同时存在加锁的动态方法和静态方法时,可以被并发访问。
总结来说,Lock和synchronized有以下几点不同:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动 通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。Lock可以让等待锁的线程响应中断,而synchronized 却不行,使用synchronized时,等待的线程会一直阻塞,不能够响应中断;lock.trylock()能够避免死锁;
4)lock可以实现线程公平,但会使性能下降。
5)Lock可以提高多个线程进行读操作的效率。lock的读写分离,因为读之间并不会线程不安全。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock 的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
并发编程基础知识总结
1,线程创建的两种方式:继承Thread类,重写run方法,Thread t1=new ...,t.start();
实现runnable接口,Thread t2 = new Thread(....),t.start();
2,每个线程有自己的ID,name,优先级,状态(new,runnable,blocked(阻塞),waiting(无限期等待,wait(),join(),),time waiting(有限期等待,wait(),join(),sleep),terminated);
3,线程终断控制的方式:调用interrupt()线程中断函数使某线程中断后,可以通过调用t.isInterrupt()检测或者Thread.interrpted()检测,然后可以抛出InterrputedException传递这个中断信息。
5,sleep()方法让线程睡眠,让低优先级线程执行。但与wait的不同在于sleep()期间始终占着锁。而wait不占锁。
yield()方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
6,join()与wait()的区别在于wait()让自己等别人,join让别的线程等自己。,
7,守护线程是一个优先级最低的线程,当他运行结束时,整个程序也就结束了。他常作为其他线程的服务线程,不能做重要的事儿
8,线程异常处理:java的异常分为非运行时和运行时异常,非运行时需要抛出和捕获(IOex,classnotfound),运行时不需要(numberformat)。run方法不支持异常抛出,需要特殊处理。
9,继承了Thread或者实现了runnable接口的类的一个对象,如果被多个线程并发,成员变量是线程共享的,如果不想共享,可通过Threadlocal声明自己线程的私有变量。
Object o = new Object();
for(int i=0;i<10;i++) {
Thread t = new Thread(o);
t.start();
}
http://blog.youkuaiyun.com/lufeng20/article/details/24314381
10,可以通过实现ThreadFactory创建线程工厂,统一new线程。执行器框架和forkjoin框架用该方式建立线程,只不过执行器框架中所创建的是普通Thread,而forkjoin中创建的是工作者ForkJoinWorkerThread。这些类都可以被继承实现自己的线程类,但同时要实现工厂类。如果实现了自己的工厂,初始化框架的线程池时当参数传入即可。
线程是指进程中的一个执行流程,cpu调度的基本单位,虽然共享一块内存空间,但可以独立调度,独立的栈,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。
12,执行器框架(Executor Framework)(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
13,Fork/Join 框架(使用分治策略,将主任务分为多个小任务,jdk7)
与执行器框架的不同在于工作窃取算法。主任务等待他所创建子任务完成,执行这个任务的线程为工作者线程(ForkJoinWorkerThread类,thread的子类),工作者线程寻找仍未被执行的任务,并在子线程执行时间里利用所有线程优势(其实就是分治策略)。
任务继承ForkJoinTask(ForkJoinTask是个抽象类,它有两个实现类RecursiveTask和RecursiveAction前者用于不返回结果,后者用于返回结果,类似Callable和Runnable。但如果传入Runnable或者Callable,就不会使用工作窃取算法了),实现compute()(类似Run()),如果主任务范围太大,new两个范围小的子任务,然后使用invokeAll(t1,t2)进行分治。在主函数中用ForkJoinPool执行主任务。
task extends RecursiveAction {
int start,end
compute() {
if(end-start<num){
}
else {
task1 = new(midlle,end);
task2 = new(start,midlle);
invokeAll(task1,task2);
}
}
}
main() {
ForkJoinPool pool = new ForkJoinPool();
pool.excute(task);
pool.shutdown();
}
任务可以继承RecursiveTask(ForkJoinTask的子类)通过任务的get(),获得compute()的返回值,然后将子任务的返回值进行合并,作为主任务的返回值返回。
task extends RecursiveTask<>{
int start,end
compute() {
if(end-start<num){
return
}
else {
task1 = new(midlle,end);
task2 = new(start,midlle);
invokeAll(task1,task2);
return mergeRs(task1.get(),task2.get()) //这是自定义的方法
}
}
}
同步和异步执行:当用invokeAll(t1,t2)时,必须等到任务执行完毕后,方法返回;当采用fork(t)发送任务(递归),发送任务完成后立即返回,继续执行其他,然后在调用join()方法,等待子任务完成后将结果合并,并返回结果。
task extends RecursiveTask<>{
int start,end
compute() {
if(end-start<num){
return
}
else {
task1 = new(midlle,end);
task2 = new(start,midlle);
task1.fork();
task2.fork();
return mergeRs(task1.join(),task2.join());
}
}
}
compute()中可以抛出异常,调用task中的方法判断是否有异常和异常的类型,但异常抛出后程序不会停止。
任务在执行之前可以被取消。
14,并发集合(线程安全)
阻塞式集合:当集合满或者空时,被调用添加或者删除方法的线程被阻塞,直到方法能够被成功执行。阻塞队列接口和阻塞栈接口.实现原理,事实它和我们用Object.wait()、Object.notify()和非阻塞队列实现生产者-消费者的思路类似.有了这样的功能,就为多线程的排队等候的模型实现开辟了便捷通道,在执行器初始化时传入一个阻塞队列,存放任务。
如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行)
如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程。
如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
排队有三种通用策略:
直接提交。
工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
无界队列。
使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
有界队列。
当使用有限的 maximumPoolSizes时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
非阻塞:。。。。。。。。。。。。。。。。。。。。线程不会被阻塞,方法会返回null或者异常。
优先级队列,放入的每个元素必须继承compareable接口
http://www.ibm.com/developerworks/cn/java/j-jtp07233/
并发集合实现原理:
并发hashMap: http://www.cnblogs.com/yydcdut/p/3959815.html,将整个哈希表分成了16各部分,每个部分有各自的锁,这叫锁分离技术,在调用get()时并不加锁。
SynchronousQueue与java7中的TransferQueue:生产者会一直阻塞直到所添加到队列的元素被某一个消费者所消费,阻塞就是发生在元素从一个线程transfer到另一个线程的过程中,它有效地实现了元素在线程之间的传递。
http://ifeve.com/java-synchronousqueue/
http://ifeve.com/java-transfer-queue/
15 线程池 http://www.cnblogs.com/yydcdut/p/3890893.html
好处:线程复用,减少了创建和销毁线程的事件。
16,并发面试题http://www.cnblogs.com/yydcdut/p/3895956.html
如何避免死锁:java中,增大锁的粒度,Lock中的tryAcquire
死锁实现( 会写):

http://blog.youkuaiyun.com/thinkpadshi/article/details/8163751