关于JAVA的synchronized关键字,简便记忆!
synchronized关键字英文直译过来为“同步”,同步在java多线程里也可以理解为“排队”。当然它也有一个优雅的名字“互斥锁”。
synchronized可以对共享资源进行锁定,同时一刻只有一个线程可以操作它,等一个线程操作完了,再把锁释放,让下一个线程操作。这样可以保证“线程安全”。
其实结合现实生活我们不难理解,比如一辆车在同一时刻的驾驶员只有一个,能操作这辆车的也只有驾驶员自己,要是有两个人同一时间开同一辆车的话,你转一下方向盘,他转一下方向盘,那不就乱套了吗,肯定是要出事故的呀。
放在java中,如果有一个资源 i 是被线程A和线程B共享的,两个线程都要对其进行i++操作。我们知道i++这个表达式并不是原子性的,要先读取i的值,再修改。正常情况下两个线程都对其i++了,那么结果应该是2。
如果有这么一种情况 i 的初始值为0,线程A读取i的值还没来得及进行修改,线程B就已经读取到i的值了,并且在A之前进行修改,这时 i 的值被B修改为1,B修改完A才进行修改操作,那么这时A读取到的值还是B做修改之前的值0,那么此时A做修改只会基于一开始读取到的0修改加一。那么线程A和B进行的修改都是基于初始值为0修改的。这样就造成了数据错误。
如何解决这种线程不安全的问题呢?用synchronized关键字。
synchronized关键字最主要有以下3种应用方式
修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
package tongbu; public class one implements Runnable{ static int i=0; @Override public void run() { for (int j=1;j<=10000;j++){ jia(); } } public synchronized void jia(){ i++; } public static void main(String[] args) throws InterruptedException { one one= new one(); Thread t1=new Thread(one); Thread t2=new Thread(one); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
package tongbu; public class one implements Runnable{ static int i=0; @Override public void run() { for (int j=1;j<=10000;j++){ jia(); } } public static synchronized void jia(){ i++; } public static void main(String[] args) throws InterruptedException { //one one= new one(); Thread t1=new Thread(new one()); Thread t2=new Thread(new one()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
修饰静态方法和实例方法的区别是,前者可以实例化两个对象,后者只能实例化一个对象。
前者看似实例化两个对象,但由于jia()是static修饰的,两个对象操作的都是jvm里的同一个方法。
修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
package tongbu; public class one implements Runnable{ static one one=new one(); static int i=0; @Override public void run() { synchronized (one){ for (int j=1;j<=10000;j++){ i++; }} } public static void main(String[] args) throws InterruptedException { //one one= new one(); Thread t1=new Thread(one); Thread t2=new Thread(one); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
synchronized括号里放共享资源,可以是this,类的实例化对象。
因为同步锁锁的是共享的资源嘛,所以当然要放共享资源啦。
上一篇:
Java基础知识总结(2021版)
下一篇:
理解 Object 类和 Class 类