多线程第三章(1)

来源:互联网 发布:数据分析在职研究生 编辑:程序博客网 时间:2024/05/18 03:03
/**
* 当几个线程同时执行synchronized(this){}同步代码块时呈同步效果
* 当其他线程执行x对象synchronized同步方法时呈同步效果
* 当其他线程执行x对象方法里面的synchronized(this)代码块时也呈同步效果
* 如果其他线程调用不加synchronized关键字的方法时,还是异步调用
*/
/**
* 静态同步synchronized方法和synchronized(class)代码块
* 如果关键字synchronized应用在static方法上,那是对当前*.java文件对应的Class类进行持锁(适用于一个类创建多个对象,多个对象
* 起多个线程),在大多数情况下,同步synchronized代码块都不使用String作为锁对象,受常量池影响
* 死锁:不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法完成
* 在设计的时候要避免双方互相持有对方锁的情况
*/
/**
* volatile(不稳定的)关键字:使一个变量在多个线程之间可见
* 在JMM(java Memory model)中是这样处理的,在JMM中,他有一个主内存(栈内存和堆内存都可以认为是主内存),每一个线程在自己的执行当中,他有一个自己的一块内存(也包括cpu缓冲区),每个线程都有自己的一块缓冲区(把主内存里面的
* 内容读过来,在自己的缓冲区进行修改(比如说+1+1等),然后再写回去);假设另一个线程也读取了主内存中的内容,放到自己的缓冲区中,然后修改了它,把他放了回去(写回了主内存),但是第一个线程并没有重新读取主内存的内容,所以第一个线程读取
* 的还是未被修改的内容
* 如果加了volatile,不是说你在读的过程中每次都去主内存读这个内容,而是一旦主内存中的内容发生改变,就会通知其他的线程告诉他们你们的内容过期了,请重新读取
* 如果死循环里面加了sleep或者system打印,cpu可能会空闲一下,就有可能去主内存去刷新一下这个值
* volatile的效率要比synchronized高的多得多;用volatile就不用加锁(无锁同步)
* synchronized既有可见性又有原子性(要不完整的被执行,要么完全不执行),而volatile只是保证了可见性,但是效率特别高
*/
/**
* 如果只是涉及到一些简单的++,--等数据运算,java提供了一些原子类AtomXXX(饿陶蜜可),凡是以Atomic开头的都具有原子性;效率高
* AtomicInteger count = new AtomicInteger(0) 相当于int count =0;
* count.incrementAndGet()具有原子性,相当于count++;
*/
/**
* 当锁定一个对象a时,如果这个对象的属性发生改变,不影响锁的使用,但是如果a变成另一个对象,则锁定的对象会发生改变
*/
/**
*wait()方法:使当前的线程进行等待,将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或被中断为止,在调用wait之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步代码块中调用wait()
    * 方法,执行wait()之后,当前线程释放锁,在wait()返回前,线程与其他线程竞争重新获得锁,如果调用wait()方法时没有持有适当的锁(方法A调用的这个方法,A方法必须是加锁的),则抛异常notify()方法:也是在同步方法或同步块中调用,
    * 即在调用前,线程也必须获取该对象的对象级别锁,如果调用notify()时没有持适当的锁,也会抛异常;该方法用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,
    * 对其发出通知notify,并使她等待获取该对象的对象锁;注意:在执行完notify()方法后,当前线程并不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,要等到执行完notify()方法的线程执行完;
    * 即退出synchronized代码块,当前线程才能释放锁,而呈wait状态的线程才可以获取该对象的锁;如果该对象没有再次使用 notify语句,则即使该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,
    * 还会继续阻塞在wait状态。直到这个对象发出一个 notify或 notifyAll(仅通知一个)
    *
    *notifyAll()方法:让所有等待队列中等待同一共享资源的“全部”线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行,但也有可能是随机执行;当线程呈wait()状态时,调用线程对象的interrupt方法会出现InterruptException异常
    * 总结:wait使线程停止运行,而 notify使停止的线程继续运行;如果想让notify停止,则在他里面加一个wait()方法即可
    */
/**
* 使用Latch(门闩)替代wait notify来进行通知,使用await()和countdown()方法代替wait和notify,CountDownLatch不涉及到锁定,当count值为0时当前线程继续运行,当不涉及同步时,用synchronized+wait/notify显得太重了
*     这时应该考虑用countdownlatch/cyclicbarrier/semaphor
*    在main方法中创建一个门闩对象CountDownLatch latch = new CountDownLatch(1);用latch.await()替换wait()方法;然后用latch.countDown()代替notify()方法(即打开门闩)即可
*/
/**
* 高并发编程3块知识点:1:synchronizer同步器  ,多个线程之间怎么进行通信,同步,步骤上的一致
*  2:同步容器:在1的基础之上,例如:ConcurrentMap,ConcurrentList等
*  3:ThreadPool,executor等 
*/
/**
* ReentrantLock(ruien春telaoke)手工锁  用于替代synchronized
*     在方法内不用加synchronized关键字,只需要在类里面创建一个ReentrantLock对象,即 Lock lock = new ReentrantLock();在调用方法1时调用lock.lock()方法,其实这个方法替代了synchronized(this),然后在finally代码
*     块中释放这个锁lock.unlock(),如果有异常需要抓,一定要在finally里面释放掉这个锁,因为他不是jvm帮你释放的,即需要手工上锁,手工释放锁

*/
/**
* ReentrantLock和synchronized区别
* 1:在使用ReentrantLock时可以进行尝试锁定,如果实在得不到这把锁我就可以退出了,我自己可以有选择;
* 第一种情况:
* void m2(){
* boolean locked =lock.tryLock();//尝试锁定
* if(locaked){ //拿到了就是true,拿不到就是false
* Syetem.out.println("我得到了这把锁");
* lock.unclock();
* }
* }
* 第二种情况:
* void m2(){
* boolean locked = false;
* try{
* locked = lock.tryLock(5,TimeUnit.SECONDS);
* if(locked){
* Syetem.out.println("我得到了这把锁");
     * }
     *    }catch(){
     * 
     * }finally{
     * if(locked){
     * lock.unclock();
     * }
* }
*
* 2:如果是synchronized,就必须等到这把锁为止,等不着也等,等到死为止;ReentrantLock更灵活一些;效率都差不多
* 3:ReentrantLock可以指定为公平锁;默认的synchronized均为不公平锁;不公平什么意思:有4个线程,第一个线程释放完对象之后,其他3个线程谁占有这个对象是随机的;并不会因为线程2比线程3等的时间长而把对象给线程2,要是公平就把
*  锁给等的时间长的线程了;即谁等的时间长给谁
* ReentrantLock() lock = new ReentrantLock(true);参数为true表示公平锁(效率低),如果不写参数表示为不公平锁
*/
/**
* 又两个线程,线程1一直占有一把锁,线程2申请不到,但是线程不想等了,怎么办?主线程把线程2打断,如果在线程2中用lock.lock()方法是打不断它的,只能傻傻等着;如果你用lock.lockInterruptibly()方法是可以打断的;
* 即其他的线程告诉线程2,你别等了,你退出吧! 
*/
/**
* ThreadLocal:线程局部变量:使用空间换时间(效率高),但是会导致内存泄漏;synchronized使用时间换空间(常用在hibernate的session)
* 线程局部变量,两个线程,有volatile关键字,线程之间是可以进行通信的,即可以修改类中的同一个变量的(对象默认为A,线程1改变他的值为B,线程2得到的值就为B,这是没有疑问的),但是我现在想自己维护自己的对象,即线程1修改完它的值
* 只让他自己用,对线程2没有任何影响,即若干个线程,自己一人一个,自己玩自己的,用ThreadLocal
* ThreadLocal<对象> t1 = new ThreadLocal<>();内存给每个线程都分配了一个t1

*/