- 修饰实例?法: 作?于当前对象实例加锁,进?同步代码前要获得当前对象实例的锁
1 /** 2 * synchronized 修饰实例?法 3 */ 4 public synchronized void increase() { 5 i++; 6 }
- 修饰静态?法: 也就是给当前类加锁,会作?于类的所有对象实例,因为静态成员不属于任何?个实例对象,是类成员( static 表明这是该类的?个静态资源,不管new了多少个对象,只有?份)。
1 public class Demo21 { 2 public static int i; 3 private synchronized static void method() { 4 System.out.println("我是类锁的第?种形式:static形式,我叫" + Thread.currentThread().getName()); 5 try { 6 Thread.sleep(1000); 7 for (int j = 0; j < 100000; j++) { 8 i++; 9 } 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 System.out.println(Thread.currentThread().getName() + "1=" + i); 14 } 15 }
- 修饰代码块: 指定加锁对象,对给定对象加锁,进?同步代码库前要获得给定对象的锁。
1 private void method2() { 2 synchronized (Demo21.class) { 3 // synchronized (this) { 4 System.out.println("我是类锁的第?种形式:static形式,我叫" + 5 Thread.currentThread().getName()); 6 try { 7 Thread.sleep(1000); 8 for (int j = 0; j < 100000; j++) { 9 i++; 10 } 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 System.out.println(Thread.currentThread().getName() + "1=" + i); 15 } 16 }
- 同步代码块的情况
?先切换到类的对应?录执? javac XXX.java 命令?成编译后的.class ?件,然后执? javap -c -s -v -l XXX.class。
synchronized 同步语句块的实现使?的是 monitorenter 和 monitorexit 指令,其中monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。 当执? monitorenter 指令时,线程试图获取锁也就是获取 monitor(monitor对象存在于 每个Java对象的对象头中,synchronized 锁便是通过这种?式获取锁的,也是为什么Java中任意对象可以作为锁的原因) 的持有权。 当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在执?monitorexit 指令后,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外?个线程释放为?。
- 同步方法的情况
?先切换到类的对应?录执? javac XXX.java 命令?成编译后的 .class ?件,然后执? javap -c -s -v -l XXX.class。
synchronized 修饰的?法并没有 monitorenter 指令和 monitorexit 指令,取得代之的却是ACC_SYNCHRONIZED 标识,该标识指明了该?法是?个同步?法,JVM 通过该ACC_SYNCHRONIZED 访问标志来辨别?个?法是否声明为同步?法,从?执?相应的同
- 偏向锁
引?偏向锁的?的和引?轻量级锁的?的很像,他们都是为了没有多线程竞争的前提下,减少传统的重量级锁使?操作系统互斥量产?的性能消耗。但是不同是:轻量级锁在?竞争的情况下使?CAS 操作去代替使?互斥量。?偏向锁在?竞争的情况下会把整个同步都消除掉。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要花费CAS操作来加锁和解锁,而只需简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁,如果测试成功,表示线程已经获得了锁,如果测试失败,则需要再测试下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁),如果没有设置,则使用CAS竞争锁,竞争成果后为轻量级锁如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。
- 轻量级锁
- 自旋锁和自适应自旋
轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层?挂起,还会进??项称为?旋锁的优化?段。
互斥同步对性能最?的影响就是阻塞的实现,因为挂起线程/恢复线程的操作都需要转?内核态中完成(?户态转换到内核态会耗费时间)。
- 锁消除
锁消除理解起来很简单,它指的就是虚拟机即使编译器在运?时,如果检测到那些共享数据不可能存在竞争,那么就执?锁消除。锁消除可以节省毫?意义的请求锁的时间。
- 锁粗化
原则上,我们在编写代码的时候,总是推荐将同步块的作?范围限制得尽量?,——直在共享数据的实际作?域才进?同步,这样是为了使得需要同步的操作数量尽可能变?,如果存在锁竞争,那等待线程也能尽快拿到锁。
- 两者都是可重?锁
- synchronized 依赖于 JVM ? ReenTrantLock 依赖于 API
- ReenTrantLock ? synchronized 增加了?些?级功能
-
- ReenTrantLock提供了?种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
- ReenTrantLock可以指定是公平锁还是?公平锁。?synchronized只能是?公平锁。所谓的公平锁就是先等待的线程先获得锁。 ReenTrantLock默认情况是?公平的,可以通过ReenTrantLock类的 ReentrantLock(boolean fair) 构造?法来制定是否是公平的。
- synchronized关键字与wait()和notify/notifyAll()?法相结合可以实现等待/通知机制,ReentrantLock类当然也可以实现,但是需要借助于Condition接?与newCondition() ?法。Condition是JDK1.5之后才有的,它具有很好的灵活性,?如可以实现多路通知功能也就是在?个Lock对象中可以创建多个Condition实例(即对象监视器),线程对象可以注册在指定的Condition中,从?可以有选择性的进?线程通知,在调度线程上更加灵活。 在使?notify/notifyAll()?法进?通知时,被通知的线程是由 JVM 选择的,?ReentrantLock类结合Condition实例可以实现“选择性通知” ,这个功能?常重要,?且是Condition接?默认提供的。?synchronized关键字就相当于整个Lock对象中只有?个Condition实例,所有的线程都注册在它?个身上。如果执?notifyAll()?法的话就会通知所有处于等待状态的线程这样会造成很?的效率问题,?Condition实例的signalAll()?法 只会唤醒注册在该Condition实例中的所有等待线程。
不可变对象
- 所有成员变量必须是private
- 最好同时?final修饰(?必须)
- 不提供能够修改原有对象状态的?法
-
最常?的?式是不提供setter?法
-
如果提供修改?法,需要新创建?个对象,并在新创建的对象上进?修改
-
-
getter?法不能对外泄露this引?以及成员变量的引?
- java.util.Collections#unmodifiableCollection
- java.util.Collections#unmodifiableSet
- java.util.Collections#unmodifiableSortedSet
- java.util.Collections#unmodifiableNavigableSet
- java.util.Collections#unmodifiableList
- java.util.Collections#unmodifiableMap
- java.util.Collections#unmodifiableSortedMap
- java.util.Collections#unmodifiableNavigableMap
- 修饰类(禁?继承)
- 修饰?法(禁??类覆盖,注意现在已经不需要因为效率把?法设置为final了)
- final修饰的变量称为常量
- final修饰的引?类型变量 是引?不可变,?对象不可变
线程不安全类 | 线程安全类 |
StringBuilder | StringBuffer |
SimpleDateFormat | JodaTime |
ArrayList | CopyOnWriteArrayList |
HashSet,TreeSet | CopyOnWriteArraySet,ConcurrentSkipListSet |
HashMap,TreeMap | ConcurrentHashMap,ConcurrentSkipListMap |
。。。 | 。。。 |
-
CopyOnWriteArrayList
实现原理:CopyOnWriterArrayList 允许并发的读,读操作是?锁的,性能较?。写操作的话,?如向容器增加?个元素,则?先将当前容器复制?份,然后在新副本上执?写操作,结束之后再将原容器的引?指向新容器。