设为首页 加入收藏

TOP

Java并发编程:synchronized(二)
2015-07-26 20:41:54 来源: 作者: 【 】 浏览:136
Tags:Java 并发 编程 synchronized
程无法同时访问该代码块。


  synObject可以是this,代表获取当前对象的锁,也可以是类中的一个属性,代表获取该属性的锁。


  比如上面的insert方法可以改成以下两种形式:


class InsertData {


? ? private ArrayList arrayList = new ArrayList();


? ?


? ? public void insert(Thread thread){


? ? ? ? synchronized (this) {


? ? ? ? ? ? for(int i=0;i<100;i++){


? ? ? ? ? ? ? ? System.out.println(thread.getName()+"在插入数据"+i);


? ? ? ? ? ? ? ? arrayList.add(i);


? ? ? ? ? ? }


? ? ? ? }


? ? }


}


class InsertData {


? ? private ArrayList arrayList = new ArrayList();


? ? private Object object = new Object();


? ?


? ? public void insert(Thread thread){


? ? ? ? synchronized (object) {


? ? ? ? ? ? for(int i=0;i<100;i++){


? ? ? ? ? ? ? ? System.out.println(thread.getName()+"在插入数据"+i);


? ? ? ? ? ? ? ? arrayList.add(i);


? ? ? ? ? ? }


? ? ? ? }


? ? }


}


  从上面可以看出,synchronized代码块使用起来比synchronized方法要灵活得多。因为也许一个方法中只有一部分代码只需要同步,如果此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就可以避免这个问题,synchronized代码块可以实现只对需要同步的地方进行同步。


  另外,每个类也会有一个锁,它可以用来控制对static数据成员的并发访问。


  并且如果一个线程执行一个对象的非static synchronized方法,另外一个线程需要执行这个对象所属类的static synchronized方法,此时不会发生互斥现象,因为访问static synchronized方法占用的是类锁,而访问非static synchronized方法占用的是对象锁,所以不存在互斥现象。


看下面这段代码就明白了:


public class Test {


? ? public static void main(String[] args)? {


? ? ? ? final InsertData insertData = new InsertData();


? ? ? ? new Thread(){


? ? ? ? ? ? @Override


? ? ? ? ? ? public void run() {


? ? ? ? ? ? ? ? insertData.insert();


? ? ? ? ? ? }


? ? ? ? }.start();?


? ? ? ? new Thread(){


? ? ? ? ? ? @Override


? ? ? ? ? ? public void run() {


? ? ? ? ? ? ? ? insertData.insert1();


? ? ? ? ? ? }


? ? ? ? }.start();


? ? }?


}


class InsertData {?


? ? public synchronized void insert(){


? ? ? ? System.out.println("执行insert");


? ? ? ? try {


? ? ? ? ? ? Thread.sleep(5000);


? ? ? ? } catch (InterruptedException e) {


? ? ? ? ? ? e.printStackTrace();


? ? ? ? }


? ? ? ? System.out.println("执行insert完毕");


? ? }


? ?


? ? public synchronized static void insert1() {


? ? ? ? System.out.println("执行insert1");


? ? ? ? System.out.println("执行insert1完毕");


? ? }


}


  执行结果;



  第一个线程里面执行的是insert方法,不会导致第二个线程执行insert1方法发生阻塞现象。


  下面我们看一下synchronized关键字到底做了什么事情,我们来反编译它的字节码看一下,下面这段代码反编译后的字节码为:


public class InsertData {


? ? private Object object = new Object();


? ?


? ? public void insert(Thread thread){


? ? ? ? synchronized (object) {


? ? ? ?


? ? ? ? }


? ? }


? ?


? ? public synchronized void insert1(Thread thread){


? ? ? ?


? ? }


? ?


? ? public void insert2(Thread thread){


? ? ? ?


? ? }


}



  从反编译获得的字节码可以看出,synchronized代码块实际上多了monitorenter和monitorexit两条指令。monitorenter指令执行时会让对象的锁计数加1,而monitorexit指令执行时会让对象的锁计数减1,其实这个与操作系统里面的PV操作很像,操作系统里面的PV操作就是用来控制多个线程对临界资源的访问。对于synchronized方法,执行中的线程识别该方法的 method_info 结构是否有 ACC_SYNCHRONIZED 标记设置,然后它自动获取对象的锁,调用方法,最后释放锁。如果有异常发生,线程自动释放锁。  


  有一点要注意:对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇JavaScript跨浏览器事件对象类库 下一篇Java并发编程实战(使用synchroni..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: