多线程笔记

1.多线程的建立方式有两种   a 实现Runnable的接口 实现他的run的方法 建议使用这种 由于接口能够实现多继承   b 集成Thread 的抽象类,重写父类的 run的方法。 2.run() 与start()的区别   调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,仍是在主线程里执行。   把须要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。而且run()方法必须是public访问权限,返回值类型为void. 3.多线程的Synchronized   a Synchronized 须要锁住对象,否则的话仍是会互斥。   b 静态方法和实例方法同步的话须要锁住 class自己,(静态方法须要同步只有锁住字节码的对象才能够 Object.class)   c 要用到共同数据,最好所有在同一个类中实现,既能够达到高内聚,也能够实现同步锁。 4.sleep和wait的区别   a sleep来自Thread类,和wait来自Object类。   b 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其余线程可使用同步控制块或者方法。   c wait等待的线程能够用 notify 唤醒。这个能够用while 循环一块儿使用能够防止伪唤醒,由于有时候没用调用notify的时候也能够唤醒线程。   d 在wait()/notify()机制中,不要使用全局对象,字符串常量等。应该使用对应惟一的对象。   public void method(){ while(true){ wait(); ........ notify(); }   } 5.线程共享变量   a ThreadLocal 不是用来解决共享对象的多线程访问问题的,通常状况下,经过ThreadLocal.set() 到线程中的对象是该线程本身使用的对象,其余线程是不须要访问的,也访问不到的。   b 也能够用HashMap类来实现这个功能,map.put(当前线程,须要该线程共享的值);   c ThreadLocal 的具体实现是 ThreadLocalMap 这个map的具体key是当前线程。该类的set方法与下面相似用来取值;   d 一个ThreadLocal只能放一个变量 若是有多个的话能够用一个实体封装。或者新建多个ThreadLocal对象;    public T get() {     //获取当前执行线程     Thread t = Thread.currentThread();     //取得当前线程的ThreadLocalMap实例     ThreadLocalMap map = getMap(t);     //若是map不为空,说明该线程已经有了一个ThreadLocalMap实例     if (map != null) {         //map中保存线程的全部的线程本地变量,咱们要去查找当前线程本地变量         ThreadLocalMap.Entry e = map.getEntry(this);         //若是当前线程本地变量存在这个map中,则返回其对应的值         if (e != null)             return (T)e.value;     }     //若是map不存在或者map中不存在当前线程本地变量,返回初始值     return setInitialValue(); } 6.Thread.stop()  方法是不安全的. 释放该线程所持有的全部的锁,那么被保护数据就有可能呈现不一致性,其余线程在使用这些被破坏的数据时,有可能致使一些很奇怪的应用程序错误。 7.如何正确中止线程 关于如何正确中止线程,这篇文章(how to stop thread)给出了一个很好的答案, 总结起来就下面3点(在中止线程时): 1. 使用violate boolean变量来标识线程是否中止 2. 中止线程时,须要调用中止线程的interrupt()方法,由于线程有可能在wait()或sleep(), 提升中止线程的即时性 3. 对于blocking IO的处理,尽可能使用InterruptibleChannel来代替blocking IO 总结: 1.局部变量中的基本数据类型(8种)永远是线程安全的。 2.局部变量中的对象类型只要不会被其余线程访问到,也是线程安全的。 3.一个对象实例被多个线程同时访问时,他的成员变量就多是线程不安全的。 =========================================================================== java.util.concurrent 线程并发包 (compareAndSet)CAS同步的原理:http://www.blogjava.net/syniii/archive/2010/11/18/338387.html?opt=admin CAS有3个操做数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作。 利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。 CAS看起来很爽,可是会致使“ABA问题”。 CAS算法实现一个重要前提须要取出内存中某时刻的数据,而在下时刻比较并替换,那么在这个时间差类会致使数据的变化。 好比说一个线程one从内存位置V中取出A,这时候另外一个线程two也从内存中取出A,而且two进行了一些操做变成了B,而后two又将V位置的数据变成A,这时候线程one进行CAS操做发现内存中仍然是A,而后one操做成功。尽管线程one的CAS操做成功,可是不表明这个过程就是没有问题的。若是链表的头在变化了两次后恢复了原值,可是不表明链表就没有变化。所以前面提到的原子操做AtomicStampedReference/AtomicMarkableReference就颇有用了。这容许一对变化的元素进行原子操做。 java.util.concurrent.AtomicInteger : AtomicInteger,一个提供原子操做的Integer的类。在Java语言中,++i和i++操做并非线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则经过一种线程安全的加减操做接口。         采用的是compareAndSet CAS来保证数据的同步,是经过CPU来实现的,比起用synchronized, 这里的排他时间要短的多. 因此在多线程状况下性能会比较好. ========================================================================================================= 线程池 参考文档:http://www.oschina.net/question/565065_86540 线程池的做用:线程池做用就是限制系统中执行线程的数量。根据系统的环境状况,能够自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了形成系统拥挤效率不高。用线程池控制线程数量,其余线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务须要运行时,若是线程池中有等待的工做线程,就能够开始运行了;不然进入等待队列。 为何要用线程池:1.减小了建立和销毁线程的次数,每一个工做线程均可以被重复利用,可执行多个任务。 2.能够根据系统的承受能力,调整线程池中工做线线程的数目,防止由于消耗过多的内存,而把服务器累趴下(每一个线程须要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。 Java里面线程池的顶级接口是Executor,可是严格意义上讲Executor并非一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。 ExecutorService 真正的线程池接口。 ScheduledExecutorService 能和Timer/TimerTask相似,解决那些须要任务重复执行的问题。 ThreadPoolExecutor ExecutorService的默认实现。 ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。 1. newSingleThreadExecutor 建立一个单线程的线程池。这个线程池只有一个线程在工做,也就是至关于单线程串行执行全部任务。若是这个惟一的线程由于异常结束,那么会有一个新的线程来替代它。此线程池保证全部任务的执行顺序按照任务的提交顺序执行。 2.newFixedThreadPool 建立固定大小的线程池。每次提交一个任务就建立一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,若是某个线程由于执行异常而结束,那么线程池会补充一个新线程。 3. newCachedThreadPool 建立一个可缓存的线程池。若是线程池的大小超过了处理任务所须要的线程, 那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增长时,此线程池又能够智能的添加新线程来处理任务。此线程池不会对线程池大小作限制,线程池大小彻底依赖于操做系统(或者说JVM)可以建立的最大线程大小。 4.newScheduledThreadPool 建立一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。 以上的全部底层实现都是用ThreadPoolExecutor这个来作的。具体的能够查看源代码 ================================================================================================================= Callable 与 Future 的应用 配合使用能够获得每一个线程的返回值 Callable返回 Future接收 ================================================================================================================= java.util.concurrent.Lock : 共同点:Lock可以完成synchronized所实现的全部功能 不一样点:Lock有比synchronized更精确的线程和更好的性能,而且提供了多样化的同步,好比有时间限制的同步,能够被Interrupt的同步(synchronized的同步是不能Interrupt的)等。 synchronized是在JVM层面上实现的,在代码执行时出现异常,JVM会自动释放锁定.但Lock不能,只能手动释放,而且在finally从句中释放   性能:在jdk1.5中Synchronized是使用的独占悲观锁,资源竞争不激烈的状况下synchronized性能略高,资源竞争激烈的状况下性能要远低于Lock。         jdk1.6后synchronized和lock同样都是使用CAS乐观锁操做,因此性能差很少,对于具体使用哪个要看具体的系统应用须要,Synchronized相对简单易用,若须要精细的灵活控制则能够考虑选择lock。 Lock 也是采用compareAndSetState CAS 机制来实现锁的 ReentrantLock 互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5以前, 咱们一般使用synchronized机制控制多个线程对共享资源的访问。而如今Lock提供了比synchronized机制更普遍灵活的锁定操做。 ================================================================================================================= ReadWriteLock 读写锁 ReentrantReadWriteLock 和 ReentrantLock 不是继承关系,但都是基于 AbstractQueuedSynchronizer 来实现。 注意:在同一线程中,持有读锁后,不能直接调用写锁的lock方法 ,不然会形成死锁。 读 写 读 容许 不容许 写 不容许 不容许 ================================================================================================================= Condition  能够实现可阻塞队列。可参考api里的经典列子 Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用 Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例得到 Condition 实例,请使用其 newCondition() 方法。 class BoundedBuffer {    final Lock lock = new ReentrantLock();    final Condition notFull  = lock.newCondition();     final Condition notEmpty = lock.newCondition();     final Object[] items = new Object[100];    int putptr, takeptr, count;    public void put(Object x) throws InterruptedException {      lock.lock();      try {        while (count == items.length)           notFull.await();        items[putptr] = x;         if (++putptr == items.length) putptr = 0;        ++count;        notEmpty.signal();      } finally {        lock.unlock();      }    }    public Object take() throws InterruptedException {      lock.lock();      try {        while (count == 0)           notEmpty.await();        Object x = items[takeptr];         if (++takeptr == items.length) takeptr = 0;        --count;        notFull.signal();        return x;      } finally {        lock.unlock();      }    }   } ================================================================================================================= 自旋锁 :相似于while死循环,不断的判断表达式,判断是否还持有该把锁对象.         会致使死锁。若是长期持有自旋锁 独占悲观锁:synchronized CAS乐观锁 :Lock
相关文章
相关标签/搜索