Java Keyword Synchronized 学习记录
程序员文章站
2022-06-28 21:16:34
Synchronized Java编程思想:每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分,调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方法,除非第一个方法完成了自己的工作,并解除锁定。 特点:Jvm层面,非公平, ......
synchronized
java编程思想:每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分,调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方法,除非第一个方法完成了自己的工作,并解除锁定。
特点:jvm层面,非公平,悲观,独占,可重入,重量级。
作用:修饰方法和代码块。
修饰方法和代码块
synchronized修饰静态方法,我们可以称其为“类锁”,即只要有一个线程实例对象获取该锁,其他线程实例对象都需要等待。修饰非静态方法,我们称之为对象锁,即不同的线程实例对象是可以调用同一类下的同步方法。
/** * @packagename com.a.squirrel.synchronize * @author: squirrel * @date: 2018/6/25 10:04 * @description: synchronized解析辅助类 */ public class synchronizeddescription { private string tmpstr; private int tmpint; /** * @author squirrel * @description 非静态同步方法 * @date 2018/6/25 * @param [synchronizeddescription] * @return **/ public synchronized void testsynchronizedmethod(synchronizeddescription synchronizeddescription){ system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:==========我是非静态同步方法======="); system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:调用非静态同步方法时间为:"+getnowtime()); try { thread.sleep(5000);// 当前线程休眠5s,休眠过程中不会释放锁 } catch (interruptedexception e) { e.printstacktrace(); } } /** * @author squirrel * @description 同步代码块 * @date 2018/6/25 * @param [synchronizeddescription] * @return **/ public void testsynchronizedblockmethod(synchronizeddescription synchronizeddescription){ synchronized (synchronizeddescription){// 锁定实例对象 system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:==========我是同步代码块======="); system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:调用同步代码块时间为:"+getnowtime()); try { thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁 } catch (interruptedexception e) { e.printstacktrace(); } } } /** * @author squirrel * @description 静态同步方法 * @date 2018/6/25 * @param [synchronizeddescription] * @return **/ public synchronized static void testsynchronizedstaticmethod(synchronizeddescription synchronizeddescription){ system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:==========我是静态同步方法======="); system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:调用静态同步方法时间为:"+getnowtime()); try { thread.sleep(10000);// 当前线程休眠10s,休眠过程中不会释放锁 } catch (interruptedexception e) { e.printstacktrace(); } } /** * @author squirrel * @description 获取当前时间 * @date 2018/6/25 * @param [] * @return java.lang.string **/ private static string getnowtime(){ return new simpledateformat("yyyy-mm-dd hh:mm:ss").format(new date()); } public synchronizeddescription(string tmpstr, int tmpint) { this.tmpstr = tmpstr; this.tmpint = tmpint; } public string gettmpstr() { return tmpstr; } public void settmpstr(string tmpstr) { this.tmpstr = tmpstr; } public int gettmpint() { return tmpint; } public void settmpint(int tmpint) { this.tmpint = tmpint; } }
/** * @packagename com.a.squirrel.synchronize * @author: squirrel * @date: 2018/6/25 10:10 * @description: 测试类 */ public class testsynchronized { public static void main(string[] args) { // 创建阻塞队列 final blockingqueue<runnable> queue = new arrayblockingqueue<>(100); // 创建线程池 final threadpoolexecutor threadpool = new threadpoolexecutor(2,20,60, timeunit.seconds,queue); threadpool.allowcorethreadtimeout(true); for (int i =0;i<100;i++){ threadpool.execute(new runnable() { @override public void run() { final string tmpstr = thread.currentthread().getname(); final string[] split = tmpstr.split("-"); int tmpint = integer.parseint(split[split.length-1]); synchronizeddescription synchronizeddescription = new synchronizeddescription(tmpstr,tmpint); // 调用同步代码块 synchronizeddescription.testsynchronizedblockmethod(synchronizeddescription); // 调用非静态同步方法 synchronizeddescription.testsynchronizedmethod(synchronizeddescription); // 调用静态同步方法 synchronizeddescription.testsynchronizedstaticmethod(synchronizeddescription); } }); } } }
运行结果可以验证以上结论:
下面我们变更同步代码块的同步对象:
/** * @author squirrel * @description 同步代码块 * @date 2018/6/25 * @param [synchronizeddescription] * @return **/ public void testsynchronizedblockmethod(synchronizeddescription synchronizeddescription){ synchronized (synchronizeddescription.class){// 锁定类对象 system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:==========我是同步代码块======="); system.out.println("线程:"+synchronizeddescription.gettmpint()+"-->:调用同步代码块时间为:"+getnowtime()); try { thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁 } catch (interruptedexception e) { e.printstacktrace(); } } }
由上图我们可以得出一个结论,这里借用一张图来说明一下这个结论:
实现原理:
深入理解java虚拟机:对象在内存中存储的布局可以分为3块区域:对象头,实例数据和对齐填充。
synchronized对象锁其指针指向的是一个monitor对象,每个对象实例都会有一个 monitor,其中monitor可以与对象一起创建销毁,也可以在线程试图获取对象锁时自动生成。在执行monitorenter指令时,首先要尝试获取对象锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,那么就把锁计数器加1,当执行monitorexit指令时,释放锁同时锁计数器也会减1。