synchronized关键字作用和原理

synchronized的作用:

synchronized能够在同一时刻最多只有一个线程执行该代码,已达到并发线程同步安全的效果,

synchronized能保证线程的原子性,可见性和有序性

synchronized能保证线程的原子性原理:synchronized保证只有一个线程拿到锁,即在同一时刻只有一个线程执行同步代码块或同步方法。

synchronized能保证可见性的原理:执行synchronized的方法对应的是lock原子操作会刷新线程工作内存中的共享变量,从而使其得到最新值。

synchronized能保证有序性原理:加入synchronized后,依然会发生重排序,只不过,同步代码块,可以保证只有一个线程执行同步代码块中代码,从而保证有序性。

Synchronized的地位

1.Synchronized是java的关键字,被java语言原生支持

2.是最基本的互斥同步手段

3.是并发编程的元老级角色,是并发编程的必学内容。

Synchronized的两种用法:

1.对象锁:

包括方法锁,即修饰方法(默认锁对象为this当前实例对象)和同步代码锁,修饰代码块(自己指定锁对象)

synchronized对象锁实例

方法实例1:

修饰代码块:

不加synchronized代码:

//synchronized 对象锁 实例
public class SynchronizedThis implements Runnable {	
	private static SynchronizedThis synchronizedThis=new SynchronizedThis();
	@Override
	public void run() {
		
		//synchronized (this) {
			
	
		System.out.println("线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程 "+Thread.currentThread().getName()+" 运行结束");		
		//}
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedThis,"thread1");
		Thread thread2=new Thread(synchronizedThis,"thread2");
		thread1.start();
		thread2.start();
		//线程1和线程2还存活 一直循环
		while (thread1.isAlive() || thread2.isAlive()) {
						
		}
		System.out.println("main方法运行结束");
		
	}
	
	

结果:结果可以看出线程是并发执行的

线程 thread1 开始运行
线程 thread2 开始运行
线程 thread2 运行结束
线程 thread1 运行结束
main方法运行结束客户

方法实例2:使用synchronized关键字:

public class SynchronizedThis implements Runnable {	
	private static SynchronizedThis synchronizedThis=new SynchronizedThis();
	@Override
	public void run() {		
		synchronized (this) {						
		System.out.println("线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程 "+Thread.currentThread().getName()+" 运行结束");		
		}
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedThis,"thread1");
		Thread thread2=new Thread(synchronizedThis,"thread2");
		thread1.start();
		thread2.start();
		//线程1和线程2还存活 一直循环
		while (thread1.isAlive() || thread2.isAlive()) {
						
		}
		System.out.println("main方法运行结束");
		
	}
	
	

}

运行结果:

线程 thread1 开始运行
线程 thread1 运行结束
线程 thread2 开始运行
线程 thread2 运行结束
main方法运行结束
 

从运行结果可以看出线程1和2是依次开始运行。synchronized代码块中的this是指当前对象,当然我们可以自己指定锁对象。

方法实例3:如:


//synchronized 对象锁 实例
public class SynchronizedThis implements Runnable {	
	private static SynchronizedThis synchronizedThis=new SynchronizedThis();
	 Object Object= new Object();
	
	@Override
	public void run() {
		
		synchronized (Object) {				
		System.out.println("线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程 "+Thread.currentThread().getName()+" 运行结束");		
		}
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedThis,"thread1");
		Thread thread2=new Thread(synchronizedThis,"thread2");
		thread1.start();
		thread2.start();
		//线程1和线程2还存活 一直循环
		while (thread1.isAlive() || thread2.isAlive()) {
						
		}
		System.out.println("main方法运行结束");
		
	}
	

结果:运行结果和使用this一样,

线程 thread1 开始运行
线程 thread1 运行结束
线程 thread2 开始运行
线程 thread2 运行结束
main方法运行结束
 

方法实例4:Synchronized修饰方法:同步方法

//synchronize 修饰方法
public class SynchronizedMethod implements Runnable{
	
	private static SynchronizedMethod synchronizedMethod=new SynchronizedMethod();
	
	public synchronized void method() {
		System.out.println("同步方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {	
		method();
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedMethod,"Thread1");
		Thread thread2=new Thread(synchronizedMethod,"Thread2");
		thread1.start();
		thread2.start();
		
		while (thread1.isAlive() || thread2.isAlive()) {
			
		}		
		System.out.println("main 运行结束");
	}	

结果:线程是依次执行的

同步方法 线程 Thread1 开始运行
同步方法  线程 Thread1 运行结束
同步方法 线程 Thread2 开始运行
同步方法  线程 Thread2 运行结束
main 运行结束

2.类锁:

指synchronized修饰静态方法或指定锁对象为class对象。类锁只能在同一时刻被一个线程拥有。

类锁有两中形式:

1.Synchronized修饰静态方法(static 方法)

方法实例5:synchronized修饰普通方法,但线程运行使用不同对象

// synchronize 类锁 修饰static方法
public class SynchronizedClass implements Runnable {
	private static SynchronizedClass SynchronizedClass1=new SynchronizedClass();
	private static SynchronizedClass SynchronizedClass2=new SynchronizedClass();
	
	public synchronized void method() {
		System.out.println("同步方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {
		method();
		
	}
	public static void main(String[] args) {
		Thread thread1=new Thread(SynchronizedClass1,"Thread1");
		Thread thread2=new Thread(SynchronizedClass2,"Thread2");
		thread1.start();
		thread2.start();		
		while (thread1.isAlive() || thread2.isAlive()) {			
		}		
		System.out.println("main 运行结束");
	}

结果:从结果看出虽然方法用的synchronized修饰  线程1和2是并发并发执行的,因为线程1使用的对象SynchronizedClass1而线程2使用的是对象SynchronizedClass2,两个线程使用的不同的对象,而synchronized修饰普通方法是以this当前对象为锁,线程1this对象是SynchronizedClass1,线程2this对象是SynchronizedClass2,所以两线程运行没有影响。

同步方法 线程 Thread1 开始运行
同步方法 线程 Thread2 开始运行
同步方法  线程 Thread2 运行结束
同步方法  线程 Thread1 运行结束
main 运行结束

方法实例6:synchronized修饰static方法,但线程运行使用不同对象

// synchronize 类锁 修饰static方法
public class SynchronizedClass implements Runnable {
	private static SynchronizedClass SynchronizedClass1=new SynchronizedClass();
	private static SynchronizedClass SynchronizedClass2=new SynchronizedClass();
	
	public static synchronized void method() {
		System.out.println("同步方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {
		method();
		
	}
	public static void main(String[] args) {
		Thread thread1=new Thread(SynchronizedClass1,"Thread1");
		Thread thread2=new Thread(SynchronizedClass2,"Thread2");
		thread1.start();
		thread2.start();		
		while (thread1.isAlive() || thread2.isAlive()) {			
		}		
		System.out.println("main 运行结束");
	}

结果:结果看出是线程1运行结束后线程2运行,因为synchronized修饰静态方法是依class对象为锁,虽然线程1和线程2使用的是不同的对象,但SynchronizedClass1,SynchronizedClass2都对应唯一的class对象。

同步方法 线程 Thread1 开始运行
同步方法  线程 Thread1 运行结束
同步方法 线程 Thread2 开始运行
同步方法  线程 Thread2 运行结束
main 运行结束

2.Synchronized代码块 synchronized(*.class)

方法实例7::synchronized(this)代码块

// synchronize 类锁 代码块 synchronized(*.calss)
public class SynchronizedClass implements Runnable {
	private static SynchronizedClass SynchronizedClass1=new SynchronizedClass();
	private static SynchronizedClass SynchronizedClass2=new SynchronizedClass();
	
	public  void method() {
		synchronized (this) {
			System.out.println("代码块 线程 "+Thread.currentThread().getName()+" 开始运行");
			try {
				Thread.sleep(3000);//休眠2秒			
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("代码块  线程 "+Thread.currentThread().getName()+" 运行结束");	
			
		}
								
	} 

	@Override
	public void run() {
		method();
		
	}
	public static void main(String[] args) {
		Thread thread1=new Thread(SynchronizedClass1,"Thread1");
		Thread thread2=new Thread(SynchronizedClass2,"Thread2");
		thread1.start();
		thread2.start();		
		while (thread1.isAlive() || thread2.isAlive()) {			
		}		
		System.out.println("main 运行结束");
	}

结果:两线程同时执行

代码块 线程 Thread2 开始运行
代码块 线程 Thread1 开始运行
代码块  线程 Thread2 运行结束
代码块  线程 Thread1 运行结束
main 运行结束

方法实例8:synchronized(SynchronizedClass.class)代码块

// synchronize 类锁 代码块 synchronized(*.calss)
public class SynchronizedClass implements Runnable {
	private static SynchronizedClass SynchronizedClass1=new SynchronizedClass();
	private static SynchronizedClass SynchronizedClass2=new SynchronizedClass();
	
	public  void method() {
		synchronized (SynchronizedClass.class) {
			System.out.println("代码块 线程 "+Thread.currentThread().getName()+" 开始运行");
			try {
				Thread.sleep(3000);//休眠2秒			
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("代码块  线程 "+Thread.currentThread().getName()+" 运行结束");	
			
		}
								
	} 

	@Override
	public void run() {
		method();
		
	}
	public static void main(String[] args) {
		Thread thread1=new Thread(SynchronizedClass1,"Thread1");
		Thread thread2=new Thread(SynchronizedClass2,"Thread2");
		thread1.start();
		thread2.start();		
		while (thread1.isAlive() || thread2.isAlive()) {			
		}		
		System.out.println("main 运行结束");
	}

结果:线程依次运行结果和修饰静态方法。

代码块 线程 Thread1 开始运行
代码块  线程 Thread1 运行结束
代码块 线程 Thread2 开始运行
代码块  线程 Thread2 运行结束
main 运行结束

 问题:多线程访问同步方法的7中情况(线程怎样执行)

1.两个线程同时访问一个对象的同步方法(synchronized 修饰普通方法)

答:访问同一个对象的同步方法,线程串行执行,参考 方法实例4

2.两个线程访问的是两个对象的同步方法(synchronized 修饰普通方法)

答:两线程并发执行,参考 方法实例5

3.两个线程访问的是synchronized的静态方法(两个对象)

答:线程串行执行,参考  方法实例6

4.两线程一个访问同步方法与另一个访问非同步方法

答  :访问同步方法不会影响另一个访问非同步方法


public class SynchronizedMethod implements Runnable{
	
	private static SynchronizedMethod synchronizedMethod=new SynchronizedMethod();
	
	public synchronized void method1() {
		System.out.println("同步方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 
	
	public  void method2() {
		System.out.println("非同步方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("非同步方法  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {	
		if (Thread.currentThread().getName().equals("Thread1")) {
			method1();
		}else {
			method2();
		}
		
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedMethod,"Thread1");
		Thread thread2=new Thread(synchronizedMethod,"Thread2");
		thread1.start();
		thread2.start();
		
		while (thread1.isAlive() || thread2.isAlive()) {
			
		}		
		System.out.println("main 运行结束");
	}	

结果:线程1不影响线程2的执行

非同步方法 线程 Thread2 开始运行
同步方法 线程 Thread1 开始运行
非同步方法  线程 Thread2 运行结束
同步方法  线程 Thread1 运行结束
main 运行结束

5.访问同一个对象的不同的普通同步方法

public class SynchronizedMethod implements Runnable{
	
	private static SynchronizedMethod synchronizedMethod=new SynchronizedMethod();
	
	public synchronized void method1() {
		System.out.println("同步方法1 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法1  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 
	
	public synchronized void method2() {
		System.out.println("非同步方法2 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("非同步方法2  线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {	
		if (Thread.currentThread().getName().equals("Thread1")) {
			method1();
		}else {
			method2();
		}
		
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedMethod,"Thread1");
		Thread thread2=new Thread(synchronizedMethod,"Thread2");
		thread1.start();
		thread2.start();
		
		while (thread1.isAlive() || thread2.isAlive()) {
			
		}		
		System.out.println("main 运行结束");
	}	

结果:线程是串行执行的,

同步方法1 线程 Thread1 开始运行
同步方法1  线程 Thread1 运行结束
非同步方法2 线程 Thread2 开始运行
非同步方法2  线程 Thread2 运行结束
main 运行结束
 

 6.同;时访问一个对象的静态synchronized方法和非静态synchronized方法


public class SynchronizedMethod implements Runnable{
	
	private static SynchronizedMethod synchronizedMethod=new SynchronizedMethod();
	
	public synchronized static void method1() {
		System.out.println("同步方法1 静态方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法1 静态方法   线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 
	
	public synchronized void method2() {
		System.out.println("非同步方法2 非静态方法 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("非同步方法2 非静态方法 线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {	
		if (Thread.currentThread().getName().equals("Thread1")) {
			method1();
		}else {
			method2();
		}
		
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedMethod,"Thread1");
		Thread thread2=new Thread(synchronizedMethod,"Thread2");
		thread1.start();
		thread2.start();
		
		while (thread1.isAlive() || thread2.isAlive()) {
			
		}		
		System.out.println("main 运行结束");
	}	
	

结果:线程并发执行,因为synchronied修饰静态方法是以calss对象为锁,而非静态方法是以实例对象为锁,两线程使用的不是同一把锁,所以不影响。

同步方法1 静态方法 线程 Thread1 开始运行
非同步方法2 非静态方法 线程 Thread2 开始运行
非同步方法2 非静态方法 线程 Thread2 运行结束
同步方法1 静态方法   线程 Thread1 运行结束
main 运行结束
 

 7.方法抛出异常会释放锁

总结:

同步方法:线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。

同步块:同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;

如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块。

Synchronized性质:

1.可重入性:可重入性指同一线程的外层函数得到锁后,内层函数可以直接再次获取该锁。

可重入性的好处:避免死锁,更好的封装代码提高封装性。

Synchronized可重入性原理:synchronized的锁对象有一个计数器(recursions变量),加锁次数计数器,会记录被加锁的次数,第一次加锁时,次数从0变为1,之后再加一次锁,就从1变成2,一次类推,当退出同步方法是,计数减一,当计数为0是代表所被释放。

2.不可中断性:一个线程获得锁后,另一个线程想要获取锁,必须处于阻塞或等待状态,如果第一个线程不释放锁,另一个线程就必须处于阻塞或等待中,不可中断。

可重入性方法实例:

方法实例9:方法1和方法2都是同步方法,在方法1中调用方法2,可以执行方法2

public class SynchronizedMethod implements Runnable{
	
	private static SynchronizedMethod synchronizedMethod=new SynchronizedMethod();
	
	public synchronized  void method1() {
		System.out.println("同步方法1 线程 "+Thread.currentThread().getName()+" 开始运行");		
			method2();	
		System.out.println("同步方法1 线程 "+Thread.currentThread().getName()+" 结束");	
	} 
	
	public synchronized void method2() {
		System.out.println("同步方法2 线程 "+Thread.currentThread().getName()+" 开始运行");
		try {
			Thread.sleep(3000);//休眠2秒			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("同步方法2 线程 "+Thread.currentThread().getName()+" 运行结束");							
	} 

	@Override
	public void run() {			
			method1();
	
		
	}
	
	public static void main(String[] args) {
		Thread thread1=new Thread(synchronizedMethod,"Thread1");
		//Thread thread2=new Thread(synchronizedMethod,"Thread2");
		thread1.start();
		
		//System.out.println("main 运行结束");
	}	
	

结果:

同步方法1 线程 Thread1 开始运行
同步方法2 线程 Thread1 开始运行
同步方法2 线程 Thread1 运行结束
同步方法1 线程 Thread1 结束

 Synchronized加锁和释放锁的原理:

1.获取和释放锁的时机:进入和退出同步代码块或方法(抛出异常),进入代码块或方法是获取锁,退出方法是释放锁。

加锁和释放锁的原理:使用字节码 monitorenter获取锁,monitorexit释放锁。

 字节码 monitorenter获取锁:

每一个对象都会和一个监视器monitor关联,监视器占用时会被锁住 ,其他线程无法获取改monitor。当JVM执行某个线程的某个方法内部monitorenter时,它会尝试获取当前对象对应的monitor的所有权,其过程如下:

1.当线程执行同步代码要获取对象锁时,JVM会去检测该对象是否有关联的monitor,若没有jvm就会创建monitor对象(monitor对象是C++对象),此时monitor的进入数(记录获取锁的次数)为0,线程可以进入monitor,并将monitor的进入数置为1,当前线程成为monitor的owner(所有者)

2.若其线程拥有monitor的所有权,允许他重入monitor,则进入monitor的进入数加1

3.若其他线程已经占有monitor的所有权,那么当前尝试获取monitor的所有权的线程会被阻塞,直到monitor的进入数为0,才能重新尝试获取monitor的所有权。

monitorenter小结:

synchronized的锁对象会关联一个monitor,这个monitor不是我们主动创建的,是JVM的线程执行到这个同步代码块,发现锁对象没有monitor就会创建monitor,monitor内部有两个重要的成员变量owner:拥有这把锁的线程,recusions记录线程拥有锁的次数,当一个线程拥有monitor后其他线程只能等待。

monitorexit释放锁:

1.能执行monitorexit指令的线程一定是拥有当前对象的monitor的所有权的线程

2.执行monitorexit时会将monitor的进入数减一,当monitor的进入数减为0时,当前线程退出monitor,不在拥有monitor的所有权,此时其他被这个monitor阻塞的线程可以尝试区获取这个monitor的所有权。

说明:monitorexit插入在方法结束处和异常处,JVM保证每个monitorenter必须有对应的monitorexit

使用命令:javap -p -v *.class

对class文件进行反汇编

 静态代码块:

	public  void method() {
		synchronized (SynchronizedClass.class) {
			
			try {
				Thread.sleep(3000);		
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}							
		}								
	} 

是有上述命令对clas文件反汇编后,method方法,汇编指令:

同步方法:

	public synchronized void  method1() {
		
	}

 可以看到同步方法在反汇编后,会增加ACC_SYNCHRONIZED修饰,会隐式调用monitorenter和monitorexit。在执行同步方法前会调用monitorenter,在执行完同步方法后会调用monitorexit。

小结:通过javap反汇编可以看到synchronized使用变成了monitorentor和monitorexit这两个指令,每个锁对象都会关联一个monitor(监视器,它才是真正的锁对象)它内部有两个重要的成员变量owner会变成获得这把锁的线程,recursions会保存线程获得锁的次数,当执行到monitorexit时,recursions会减1,当计数器减到0时这个线程就会释放锁。

Synchronized的锁升级过程:

高效并发是从JDK1.5到JDK1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本上实现各种锁优化技术,包括偏向锁(Biased Locking),轻量级锁(Lightweight Locking)和适应性自旋(Adaptive Spinning)锁消除(Lock Elimination),锁粗化(Lock Coarsening)等,这些技术都是为了在线程之间更高效地共享数据,已解决竞争问题,从而提高程序的执效率

synchronized加锁过程:

先是无锁,加锁时先加偏向锁,偏向锁不行再加轻量级锁,以此类推

无锁-》偏向锁-》轻量级锁-》重量级锁

Synchronized缺陷:

1.效率低:锁的释放情况少,只有在线程调用方法结束或抛出异常时释放锁,试图获取锁是不能设置超时时间,不能中断一个试图获得锁的线程

2.不够灵活(读写锁更灵活):加锁和释放的时机单一,每个锁仅有单一的条件(某个对象),可能是不够的

3.无法知道是否成功获取到锁。

常见面试题:

1.Synchronized使用注意点:锁的范围不宜过大影响代码运行效率,要避免锁的嵌套。

2.如何选择Lock和synchronized关键字?

 总结:一句话介绍synchronized

JVM会自动通过使用monitor来加锁和解锁,保证了同时只有一个线程可以执行指定代码,从而保证了线程安全,同时具有可重入性和不可中断性质。

平时写代码对synchronized的优化:

1.减少synchronized的范围

同步代码块尽量短,减少同步代码块中代码的执行时间,减少锁的竞争。

2.降低synchronized锁的粒度

将一个锁拆分为多个锁提高并发度,

如Hashtable:锁定整个哈希表,一个操作正在进行时,其他操作也同时被锁定,效率低下。

 

 

ConcurrentHashMap:局部锁定,只锁定桶,当对当前元素锁定时,其他元素不锁定。

 

 LinkedBolckingQueue入队和出队使用不同的锁,相对于读写只有一个锁效率要高。

 3.读写分离

读取时不加锁,写入和删除时加锁。

ConcurrentHashMap,CopyOnWriteArrayList和ConyOnWriteSet

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值