java在不同情况下锁对象探索
来源:互联网 发布:virtualbox mac好用么 编辑:程序博客网 时间:2024/05/16 05:39
先从最简单的开始
***************************************
分割线 demo1
***************************************
public static void main(String args[]){ final Class1 c1 = new Class1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { c1.test1(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { c1.test1(); } }); t1.start(); t2.start();}
public class Class1 { public synchronized void test1(){ System.out.println("线程"+Thread.currentThread().getName()+"进入test1"); System.out.println("线程"+Thread.currentThread().getName()+"即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程"+Thread.currentThread().getName()+"休眠完成,释放锁");System.out.println(".........................我是一个方法结束的分割线.................................");}}打印结果如下线程Thread-0进入test1线程Thread-0即将休眠两秒当前线程Thread-0休眠完成,释放锁.........................我是一个方法结束的分割线.................................线程Thread-1进入test1线程Thread-1即将休眠两秒当前线程Thread-1休眠完成,释放锁.........................我是一个方法结束的分割线.................................***************************************
分割线 demo2
***************************************
大家对于demo1的打印结果应该没有什么疑惑,加了同步锁了,第一个线程要在里面待上两秒那么第二个线程自然需要等待,ok,我们把demo1的代码稍作修改public static void main(String args[]){ final Class1 c1 = new Class1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { c1.test1(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { c1.test2(); } }); t1.start(); t2.start();}public class Class1 { public synchronized void test1(){ System.out.println("线程"+Thread.currentThread().getName()+"进入test1"); System.out.println("线程"+Thread.currentThread().getName()+"即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程"+Thread.currentThread().getName()+"休眠完成,释放锁");System.out.println(".........................我是一个方法结束的分割线................................."); } public synchronized void test2(){ System.out.println("线程"+Thread.currentThread().getName()+"进入test2"); System.out.println("线程"+Thread.currentThread().getName()+"即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程"+Thread.currentThread().getName()+"休眠完成,释放锁");System.out.println(".........................我是一个方法结束的分割线.................................");}}打印结果如下线程Thread-0进入test1线程Thread-0即将休眠两秒当前线程Thread-0休眠完成,释放锁.........................我是一个方法结束的分割线.................................线程Thread-1进入test2
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁.........................我是一个方法结束的分割线.................................这个结果也是没有什么疑问的,同一个对象里面,两个方法都加了锁了,用两个不同的线程进行访问,自然第二个线程要等第一个线程出来之后再进去。***************************************
分割线 demo3
***************************************
继续修改,
把demo2中的test2方法修改如下
public void test2() { synchronized (this) { System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}打印结果
线程Thread-0进入test1线程Thread-0即将休眠两秒当前线程Thread-0休眠完成,释放锁.........................我是一个方法结束的分割线.................................线程Thread-1进入test2线程Thread-1即将休眠两秒当前线程Thread-1休眠完成,释放锁.........................我是一个方法结束的分割线.................................
说明什么?说明了在对象的方法上加上synchronized,则其锁对象,就是this,
下面提供一个反证。
***************************************
分割线 demo4
***************************************
把test2方法修改如下,
public String mObj = "HaHaHa";public void test2() { synchronized (mObj) { System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}则打印结果如下:线程Thread-0进入test1线程Thread-1进入test2线程Thread-0即将休眠两秒线程Thread-1即将休眠两秒当前线程Thread-1休眠完成,释放锁.........................我是一个方法结束的分割线.................................当前线程Thread-0休眠完成,释放锁.........................我是一个方法结束的分割线.................................我们看到,线程访问无序了,问什么,因为这次test1和test2用了不同的锁对象了。同时,我们还可以得出一个结论,那就是对象可以访问的非静态方法上直接加的synchronized的锁对象就是this。***************************************
分割线 demo5
***************************************
继续修改,如果我们把test2改成静态方法会怎么样?
public static synchronized void test2() { System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线.................................");}打印结果如下
线程Thread-0进入test1
线程Thread-1进入test2
线程Thread-0即将休眠两秒
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
说明什么,说明了静态方法使用的锁对象不是this,
其实想想也对,静态方法内部也无法引用的this,那么,静态方法使用的到底是哪个锁对象?
***************************************
分割线 demo6
***************************************
我们继续探索,先把test1也改成静态方法,那么
public static synchronized void test1() { System.out.println("线程" + Thread.currentThread().getName() + "进入test1"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线.................................");}线程Thread-0进入test1
线程Thread-0即将休眠两秒
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
线程Thread-1进入test2
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
说明test1和test2都申明为静态方法时,其使用的是同一把锁,那么这把锁到底是哪个对象呢?
***************************************
分割线 demo7
***************************************
继续修改,现在,我们的test1()和test2()方法都是静态方法了。
那么如果我们把test2()改为非静态方法,并且稍作修改,会怎么样
public void test2() { synchronized (Class1.class){ System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}打印结果会怎么样呢?
线程Thread-0进入test1
线程Thread-0即将休眠两秒
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
线程Thread-1进入test2
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
好吧,看来我们找到静态方法的锁了,就是字节码对象。
***************************************
分割线 demo8
***************************************
俗话说,一把钥匙开一把锁,
使用synchronized关键字的时候一定要清楚自己使用的到底使用的是哪把锁。
我们进一步修改,
public static void test1() { synchronized (Class1.class){ System.out.println("线程" + Thread.currentThread().getName() + "进入test1"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}public void test2() { synchronized (Class1.class){ System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}打印结果毫无疑问线程Thread-0进入test1线程Thread-0即将休眠两秒当前线程Thread-0休眠完成,释放锁.........................我是一个方法结束的分割线.................................线程Thread-1进入test2线程Thread-1即将休眠两秒当前线程Thread-1休眠完成,释放锁.........................我是一个方法结束的分割线.................................***************************************
分割线 demo9
***************************************
那么,既然如此,平时使用synchronized关键字的时候是否可以使用自定义的锁?当然可以。
大家都知道,java中的字符串其实是String类来封装的,其实就是个对象,
而根据java编程思想-第四版这本书的描述,所有对象都有单一的锁,
所以,可以使用字符串作为锁(其实前面的demo中已经用到了)
我们继续修改demo代码
public static String mObj = "HaHaHa";public void test1() { synchronized (mObj){ System.out.println("线程" + Thread.currentThread().getName() + "进入test1"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}public void test2() { synchronized (mObj){ System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}打印结果如下
线程Thread-0进入test1
线程Thread-0即将休眠两秒
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
线程Thread-1进入test2
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
看来,使用字符串作为锁对象,是完全成功的。
***************************************
分割线 demo10
***************************************
另外这里还有一个有趣的现象
public static String mObj = "HaHaHa";public static String mObj2 = "HaHaHa";public void test1() { synchronized (mObj){ System.out.println("线程" + Thread.currentThread().getName() + "进入test1"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}public void test2() { synchronized (mObj2){ System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}打印结果如下线程Thread-0进入test1
线程Thread-0即将休眠两秒
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
线程Thread-1进入test2
线程Thread-1即将休眠两秒
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
也就是说,如上的这种一个相同字符串重复不同变量申明两次,这样也是算一个锁的,
呵呵,这个和字符串在内存中的保存机制有关。
2:对象的静态方法将synchronized加在方法上,则锁对象为字节码文件***************************************
分割线 demo11
***************************************
public static String mObj = "HaHaHa";public static String mObj2 = "HaHaHa1";public void test1() { synchronized (mObj){ System.out.println("线程" + Thread.currentThread().getName() + "进入test1"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}public void test2() { synchronized (mObj2){ System.out.println("线程" + Thread.currentThread().getName() + "进入test2"); System.out.println("线程" + Thread.currentThread().getName() + "即将休眠两秒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程" + Thread.currentThread().getName() + "休眠完成,释放锁"); System.out.println(".........................我是一个方法结束的分割线................................."); }}修改了一下,使两个字符串不同,这个时候打印结果如下
线程Thread-1进入test2
线程Thread-0进入test1
线程Thread-1即将休眠两秒
线程Thread-0即将休眠两秒
当前线程Thread-0休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
当前线程Thread-1休眠完成,释放锁
.........................我是一个方法结束的分割线.................................
嗯,这样就不算是同一个锁了,符合预期!
总结一下
1:对象的非静态方法将synchronized加在方法上,则锁对象为this
3:任意对象都可以作为锁。
- java在不同情况下锁对象探索
- Java里如何实现一个方法在不同情况下“返回”不同的类型变量?
- Fragment在不同情况下的生命周期
- Fragment在不同情况下的生命周期
- java中final在不同情况下使用的特点作用详解
- java中异常 try,catch,finally在不同情况下的执行顺序
- java中"+"号在不同情况下的不同意义(加法运算符还是字符拼接符)
- Android手机在不同分辨率情况下字体自适应大小
- 两个程序块在不同情况下哪个更快
- Android手机在不同分辨率情况下字体自适应大小
- CString转string在unicode的情况下方法不同
- 关于viewController.view在不同情况下frame问题
- Android手机在不同分辨率情况下字体自适应大小
- Block 在不同情况下的变量存储区域
- Java 中不同情况下的线程终止
- Java中compareTo()方法在不同字符串的各种情况
- 在什么情况下使用JAVA缓存
- 百度搜索关键词排名在不同浏览器下排名不同的情况
- pdo连接数据库
- 瞧瞧 这个男孩 都做了些什么!
- Redis与Memcache的区别和应用场景
- Python import 与 from import
- hdu2088 Box of Bricks(C语言)
- java在不同情况下锁对象探索
- 【技术贴】教你彻底解决Eclipse自动补全变量名的问题
- 简单的手绘板 利用bitmap缓存
- PDO常用方法及其应用
- 2017 07 19 小结
- 2017 07 20 小结
- hdu 1114 Pig-bank
- google Guava Cache使用
- 2017 07 21 小结