synchronized
上下文切换: 程序在切换时,程序状态需要得到保存;
举个栗子:我们在看书的时候,中途去做其他事情,我们需要放书签做个标记,以便下次看书;
synchronized
理解:
1、当并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,
同一时间内只能有一个线程得到执行,另一个线程必须等待这个线程执行完代码后才可以执行该线程代码;
2、但是另一个线程可以访问该对象没有加锁的同步代码块
3、关键,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程访问
-
object的一个synchronized(this)同 步代码块都将被阻塞
4,当一个线程获
得了该对象的锁后,其他线程访问该对象的所有同步代码块都将被阻塞;
用法:
1、方法声明时使用,那么一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,
只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入。
public synchronized void synMethod() {
//方法体
}
2、对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块。
public int synMethod(Object a1){
synchronized(Object) {
//一次只能有一个线程进入
}
}
3.、synchronized
后面括号里是一对象,此时,线程获得的是对象锁。
public class MyThread implements Runnable {
public static void main(String args[]) {
MyThread mt = new MyThread();
Thread t1 = new Thread(mt, "t1");
Thread t2 = new Thread(mt, "t2");
t1.start();
t2.start();
}
public void run() {
synchronized (this) { //this为当前对象
//Thread.currentThread()显示当前线程
System.out.println(Thread.currentThread().getName());
}
}
}
注意:
如果线程进入,则得到对象锁,那么别的线程在该类所有对象上的任何操作都不能进行。在对象级使用锁通常是一种比较粗糙 的方法。将整个对象都上锁,就是不允许其他线程短暂地使用对象中其他同步方法来访问共享资源;
4、synchronized
后面括号里是类
class ArrayWithLockOrder{
synchronized(ArrayWithLockOrder.class) {
//方法体
}
}
//如果线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法,实际上,对于含有静态方法和静态变量的代码块的同步
总结:基本加锁对象
a.普通方法中锁对象为this
b.静态方法中锁对象为,当前类的.class文件
c.同步代码块中锁对象为,括号参数中指定的对象;
底层原理
tip:
想要了解synchronized底层实现,需要先用javap -c SynchronizedDemo.class
对字节码文件进行反编译
被synchronized
修饰方法使用了ACC_SYNCHRONIZED
标识符修饰,JVM
中被该标识符修饰的方法为同步方法
被synchronized修饰的对象中,会有一个monitorenter
和monitorexit
如果一个线程已经拿到了monitor ,那么另外线程去拿会失败,失败后会进入到阻塞队列中;
tip:
monitorenter
表示同步代码块开始位置
monitorexit:
表示同步代码块开结束的位置
两个monitorexit
原因:
如果程序发生异常退出了,但没有释放锁,可能发生死锁情况,加上退出指令可以保证异常情况下可以释放锁,