synchronized关键字的使用:
public synchronized void test(){} | 加在方法上,这时表示锁定的是当前对象 |
---|---|
public synchronized static void test(){} | 加在静态方法上,这时锁定的是整个类 |
sychronized(object){} | synchronized代码块,锁定的是object对象 |
一个对象里面加锁的方法和不加锁的方法可以同步执行
加锁方法执行时,不加锁的方法不受影响写方法执行时如果进行读操作,而且读操作没有加锁的话就会产生脏读(dirtyRead)copyOnWrite
public class Test2 {
private String name;
private double balance;
//一个对象里面加锁的方法和不加锁的方法可以同步执行,加锁方法执行时,不加锁的方法不受影响
public synchronized void set(String name , Double blance){
this.name=name;
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
this.balance=blance;
}
public double get(){
return this.balance;
}
//写方法执行时如果进行读操作,而且读操作没有加锁的话就会产生脏读(dirtyRead) copyOnWrite
public static void main(String args[]){
Test2 t=new Test2();
new Thread(()->t.set("zhangsan",100.0)).start();
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(t.get());
try{
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(t.get());
}
}
运行结果
set方法加了synchronized关键字,是同步方法,get方法不是同步方法。从程序中可以看出在执行set方法时,同时执行了get方法打印出了为赋值前的balance。之后再执行get方法拿到了赋值之后的值
synchronized锁是可以重入的
一个对象有两个synchronized修饰的方法,当一个线程拿到这个对象的锁执行其中一个方法时,可以再次获得这个对象的锁,即在此方法中调用另外一个同步方法
//一个同步方法可以调用另外一个同步方法,一个线程已经拥有该对象的锁,再次申请时任然会获得该对象的锁
//也就是说synchronized的锁是可以重入的
public class Test3 {
synchronized void m1(){
System.out.println("m1");
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
m2();
System.out.println(2);
}
synchronized void m2(){
try{
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("m2");
}
public static void main(String args[]){
Test3 t=new Test3();
t.m1();
}
}
m1()、m2()都是同步方法,m1()中调用了m2()方法。执行m1()时线程已经获得了t这把锁,再调用m2()方法,需要再次获得t这把锁,程序执行成功了。说明synchronized是可以重入的。
synchronized代码块里面产生异常时,程序默认会释放锁
如果产生异常时也不想释放锁,可以用try catch代码块抓住异常
public class Test6 {
int count=0;
public synchronized void m(){
while (true){
count++;
System.out.println(Thread.currentThread().getName()+" : "+count);
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
//int i=1/0;//此处抛出异常,锁将被释放,要想不被释放,可以在这里进行catch,然后继续循环
try{
if(count==5){
int i=1/0;//此处抛出异常,锁将被释放,要想不被释放,可以在这里进行catch,然后继续循环
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String args[]){
Test6 t=new Test6();
new Thread(()->t.m(),"t1").start();
try {
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
new Thread(()->t.m(),"t2").start();
}
}