多线程高并发编程总结
多线程
第一章
一。终止线程的三种方法:
1.使用退出标志,是县城正常退出,也就是当run方法完成后线程终止。
2.stop不推荐
3.使用interrupt(打了一个停止标记,并不是真的停止线程)。
1)interrupt+throw new interruptexception(推荐使用,catch块中还可以将异常向上抛,使线程停止的事件得以传播。)
2) interrupt+return
二。this.interrupted()和this.isInterrupted()
1)this.interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能。
2)测试线程Thread对象是否已经是中断状态,但不清除状态标志。
三。stop方法为什么不用?
1)已经作废,因为如果强制让线程停止则有可能使一些清理性的工作得不到完成。
2)另外一个情况就是对锁定的对象镜像了“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。
四。suspend与resume的缺点:
1)独占锁
2)不同步
五。守护进程:保姆,提供便利服务,只要当前进程实例中存在任何一个非守护进程 没有结束,守护进程就在工作,只有当最后一个非守护进程结束时,守护进程才随着jvm一同结束工作。典型应用是GC
第二章
一。synchronized锁重入:
自己可以再次获取自己的内部锁,比如有一条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获得的,如果不可锁重入的话,就会造成死锁。
二。出现异常,锁自动释放。
三。同步不具有继承性
四。在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized同步代码块时,其他线程对同一个object中所有其他synchronized同步代码块的访问将被阻塞,这说明synchronized使用的“对象监视器”是一个。
五。可以将this作为对象监视器,也可以将任意对象作为对象监视器。
六。synchroniezd(this)和synchronized同步方法的对象监视器都是对象本身。
七。锁非this对象具有一定的优点:如果在一个类中有很多的synchronized方法,这时虽然能实现同步,但会受到阻塞,所以会影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,则可以大大提高效率。
八。synchronized还可以用在static静态方法上,对类进行加锁。和对象锁是不一样的锁。
九。同步synchronized(class)代码块的作用其实和synchronized static方法的作用一样。
十。由于JVM中Strring常量池缓存的原因,在大多数的情况下,同步synchronized带麦克都不使用String作为锁对象,而改用其他,比如new Obj,但它不放入缓存池中。或者byte[] a=new byte[0];说明:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
十一,只要对象不变,即使对象的属性被改变,运行的结果还是同步。
十二。volatile:强制从公共堆栈中取得变量值,而不是从线程私有数据栈汇总取得变量的值。不支持原子性。
第三章 线程通信。
一。wait使线程停止运行,而notify使停止的线程继续运行。在调用wait之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait方法。在执行wait后,当前线程释放锁。如果调用wait时没有持有适当的锁,则抛出illegalMonitorStateException。notify调用没有持有适当的锁也会illegalMonitorStateException。
二。notify方法执行后并不立即释放锁,wait立即释放。如果发出notify操作时没有处于阻塞状态中的线程,那么该命令会被忽略。
三。 线程切换:
1)新创建一个新的线程对象后,再调用它的star()方法,系统会为此线程分配CPU资源,使其处于Runnable (可运行)状态,这是一个准备运行的阶段。如果线程抢占到CPU资源,此线程就处于Running(运行)状态。
2) Runnable状态和Running状态可相互切换,因为有可能线程运行一段时间后, 有其他高优先级的线程抢占了CPU资源,这时此线程就从Running状态变成Runnable状态。
线程进入Runnable状态大体分为如下5种情况:
口调用sleep)方法后经过的时间超过了指定的休眠时间。
口线程调用的阻塞IO已经返回,阻塞方法执行完毕。
口线程成功地获得了试图同步的监视器。
口线程正在等待某个通知,其他线程发出了通知。
口处于挂起状态的线程调用了resume恢复方法。
3) Blocked是阻塞的意思,例如遇到了一个IO操作,此时CPU处于空闲状态,可能会转而把CPU时间片分配给其他线程,这时也可以称为“暂停”状态。Blocked 状态结束后,
进人Runnable状态,等待系统重新分配资源。
出现阻塞的情况大体分为如下5种:
口线程调用seep方法,主动放弃占用的处理器资源。
口线程调用了阻塞式IO方法,在该方法返回前,该线程被阻塞。
口线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。
口线程等待某个通知。
口程序调用了suspend 方法将该线程挂起。此方法容易导致死锁,尽量避免使用该方法。
4) run(方法运行结束后进人销毁阶段,整个线程执行完毕。
四。
1.sleep方法不释放锁。notify必须执行完notify方法所在的同步synchronized代码块后才释放锁。
2.
1)执行完同步代码块就会释放对象的锁。
2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。
3)在执行同步代码块的过程中,执行了锁所属对象的wait方法,这个过程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒。
五。线程之间通信方式之:管道 pipeStream 4个类:PipeInputStream PipedReader
六。方法join:等待线程对象销毁,具有使线程排队运行的作用。有些类似同步的运行效果。join与synchronized的区别:join内部使用wait进行等待,而synchronize使用的是对象监视器原理同步。
七。join(long)和wait(long)的区别:方法join(long)功能内部是使用wait(long)来实现的,所以join方法具有释放锁的特点。
八。threadLocal类:主要解决的问题是每个线程绑定自己的值。每一个线程有自己的私有数据。
InheritableThreadLocal可以在子进程中取得父进程继承下来的值。
第四章 Lock
一。lock.lock待的线程持有了“对象监视器”,其他线程只有等待被释放时再次争抢。
二。借助condition对象可以实现多路通知的功能,也就是在一个lock对象里面可以创建多个condition(对象监视器)实例,线程对象可以注册在指定的condition中,从而有选择的进行线程通知,在调度上更灵活。在使用notify/notifyall方法进行通知时,被通知的线程时jvm随机选择的。但使用rerntrantlock结合Condition类是可以实现“选择性通知”。synchronized相当于整个lock对象只有一个单一的condition对象,所有的线程都注册在它一个对象上。
三。wait相当于condition的await。wait(long timeout)相当于await(long)。notify相当于condition的signal,notifyall相当于signalAll。
四。想要实现一对一通知,只需创建对于的condition即可。Lock lock=new ReentrantLock;Condiition condition=lock.newCondition;
五。公平锁和非公平锁,是否按照线程加锁的顺序。FIFO.创建锁的时候可以用构造方法传入。默认是非公平锁。
六。使用condition可以实现线程的按顺序执行。使用多个condition和一个变量,这个变量要一直改变使一个线程可以执行,其他线程等待。
七。读写锁ReentrantReadWriteLock,提高代码运行速度(在不需要操作实例变量的方法中)。读操作相关的锁,也称共享索女,写操作的锁,也称排它锁。也就是读读不互斥,读写互斥。写写互斥。即多个线程可以同时读取操作,但是同一时刻只允许一个Thread写入操作。
第六七章 单例模式与多线程
一。使用DCL 双检查锁机制来实现多线程环境中的延迟加载单例设计模式。
那么我们为什么要使用两个if判断这个对象当前是不是空的呢 ?因为当有多个线程同时要创建对象的时候,多个线程有可能都停止在第一个if判断的地方,等待锁的释放,然后多个线程就都创建了对象,这样就不是单例模式了,所以我们要用两个if来进行这个对象是否存在的判断。
其他方式:使用静态内置类。使用静态代码块。使用枚举类:构造方法自动调用。
二。simpledateformat非线程安全。解决方法一:创建多个simpleDateFormat。二:threadLocal
Java并发编程的艺术:
一。synchronized和lock的区别和优势
缺少了隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等synchronized不具备的同步特性。
1)尝试非阻塞地获取锁
2)能被中断地获取锁
3)超时获取锁
二。abstractQueueSynchronizer队列同步器,是用来构建锁或其他同步组件的基础框架。(不同类型的同步组件ReentrantLock、ReentrantReadWriteLock和CountDownLatch等)
三。concurrentHashMap:HashTable在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争通一把锁,假如有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问下来,这就是concurrentHashMap的锁分段技术。首先将数据分成一段一段存储,然后每一段数据配一把锁当一个线程占用锁访问期中一个段数据时,其他段的数据也能被其他线程访问。
四。CountDownLatch()和CyclicBarrier
cyclicBarrier:让一组线程到达一个屏障时被阻塞,知道最后一个线程到达屏障时,屏障才会开门,所有被屏障连接的线程才会继续进行。
countDownLatch的计数器只能使用一次,而cyclicBarrier的计数器可以使用reset方法重置。
CountDownLatch:主要是-1操作,可以用在一个线程的n个步骤,也可以是n个线程。
semaphone:可以用来做流量控制,特别是公共资源有限的场景。比如数据库连接。acquire获取、release归还。
线程间交换数据的Exchanger:用于线程间协作。线程间数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。如果一个线程先执行exchanger方法,它会一直等待第二个线程也执行,当两个线程到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。