synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入临界区,同时他还可以保证共享变量的内存可见性。
synchronized同步关键字,主要用法有同步方法,同步代码块,
主要理解几句话:
1)当一个线程正在访问一个对象的synchronized方法,那么其他线程不能访问该对象的其他synchronized方法,因为一个对象只有一个锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁。
2)当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法,因为访问非synchronized方法不需要获得该对象的锁。
3)如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象boject2的synchronized方法fun1,即使object1和object2是同一个类型(一个类new出来两个对象),也不会产线程安全问题,因为访问的不是同一个对象。
第一种:package com.ucmed.zsyy.util;
public class DirtyRead {
private String username = "zjkj";
private String password = "123";
public synchronized void setValue(String username, String password) {
System.out.println("set线程:" + Thread.currentThread().getPriority());
this.username = username;
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
this.password = password;
System.out.println("setValue最终结果:username = " + username + " , password = " + password);
}
public void getValue() {
System.out.println("get线程:" + Thread.currentThread().getPriority());
System.out.println("getValue最终结果:username = " + username + " , password = " + password);
}
public static void main(String[] args) throws InterruptedException {
final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("z3", "456");
}
});
System.out.println("主线程:" + Thread.currentThread().getPriority());
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
第二种:
package com.ucmed.zsyy.util;
public class DirtyRead {
private String username = "zjkj";
private String password = "123";
public synchronized void setValue(String username, String password) {
System.out.println("set线程:" + Thread.currentThread().getPriority());
this.username = username;
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
this.password = password;
System.out.println("setValue最终结果:username = " + username + " , password = " + password);
}
public synchronized void getValue() {
System.out.println("get线程:" + Thread.currentThread().getPriority());
System.out.println("getValue最终结果:username = " + username + " , password = " + password);
}
public static void main(String[] args) throws InterruptedException {
final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("z3", "456");
}
});
System.out.println("主线程:" + Thread.currentThread().getPriority());
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
4)理解:
这里只有一个对象,一个对象的多个synchronized修饰的方法的情况
上面例子是当get方法加上锁后,要等待set方法执行完后再执行
在方法上加synchronized关键字,持有的锁为当前对象,当一个线程调用了其中一个synchronized的方法后,其他线程再调用该类中其他synchronized修饰的方法会挂起等待,需要等上一个线程执行完,释放锁后,其他调用线程取得锁后才会执行
不是多个锁,是多个synchronized修饰的方法..这些方法是同一个锁
5):一个线程执行一个对象的非static synchronized方法,另外一个线程执行这个对象的static synchronized方法,此时不会发生互斥现象,因为static synchronized占用的是类锁,而非static synchronized方法占用的是对象锁,所以不会互斥。(我的理解:static是不需要new对象的,所以是用类锁,而非static是需要new 一个对象出来的,说以是对象锁)
注意:对于synchronized,当出现异常的时候,jvm都会自动释放当前线程占用的锁,所以异常不会导致死锁。
锁的原理及优化锁:http://cmsblogs.com/?p=2071
锁优化:锁主要的四种状态:无锁,偏向锁,轻量级锁,重量级锁,依次升级,但不能降级,是为了提高获得锁和释放锁的效率
偏向锁和轻量级锁的过程基本都是,检测Mark Word,然后标记,然后CAS竞争,修改标记,最后释放