1.什么是synchronized?
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。 ——百度百科
2.为什么要用synchronized?
synchronized用于资源被用户并发访问时避免出现脏数据。
比如:一个变量 i, 用户A把 i 赋值为10,但是还没有打印,这时候,用户B把 i 的值改成了200,A再打印的时候 i 的,显示的结果就是200
举个栗子:
public class DirtyRead {
private String username="sdf";
private String password="123";
public void setValue(String username, String password) {
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("getValue最终结果:username="+ this.username + ",password="+this.password);
}
public static void main(String[] args) throws Exception {
final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("zsd", "456");
}
});
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
当setValue方法没有用synchronized加锁,dr对象获取用户名密码就和设置的数据不一样了。因为执行setValue这个线程还没有完成,dr就对象获取用户名密码。
给setValue方法加上synchronized同步锁后,就可以保证一个线程操作完数据后,其他的数据才能访问,就会避免脏数据的情况。
3.如何用synchronized?
synchronized方法:
①当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
public synchronized void method1() {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void method2() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
final MyObject mo = new MyObject();
//t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
//t1线程先持有object对象的lock锁,t2线程如果在这个时候调用对象中的同步synchronized方法则需要等待,也就是异步
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
mo.method1();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
mo.method2();
}
},"t2");
t1.start();
t2.start();
}
打印结果:t1休眠,t2 访问了非synchronized(this)同步代码块先打印出来
②可重入锁
在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时还是可以再次得到该对象的锁的。这也证明在一个synchronized的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
“可重入锁”的概念是:自己可以再次获取自己的 内部锁,比如有1挑一线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获得这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。
static class Main{
public int i =10;
public synchronized void operationSup() {
try {
i--;
System.out.println("Main print i=" + i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Sub extends Main{
public synchronized void operationSub() {
try {
while(i > 0) {
i--;
System.out.println("Sub print i = " + i);
Thread.sleep(1000);
this.operationSup();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Sub sub = new Sub();
sub.operationSub();
}
});
t1.start();
}
未完待续……