Java同步问题_JAVA学习:多线程中的同步问题解析

【IT168技术】多线程编程中,最关键、最关心的问题应该就是同步问题,这是一个难点,也是核心。从jdk最早的版本的synchronized、volatile,到jdk 1.5中提供的java.util.concurrent.locks包中的Lock接口(实现有ReadLock,WriteLock,ReentrantLock),多线程的实现也是一步步走向成熟化。

同步,它是通过什么机制来控制的呢?第一反应就是锁,这个在学习操作系统与数据库的时候,应该都已经接触到了。在Java的多线程程序中,当多个程序竞争同一个资源时,为了防止资源的腐蚀,给第一个访问资源的线程分配一个对象锁,而后来者需要等待这个对象锁的释放。

是的,Java线程的同步,最关心的是共享资源的使用。

先来了解一些有哪些线程的共享资源:

从JVM中了解有哪些线程共享的数据是需要进行协调:一个是保存在堆中的实例变量;保存在方法区的类变量。

而在Java虚拟机加载类的时候,每个对象或类都会与一个监视器相关联,用来保护对象的实例变量或类变量;当然,如果对象没有实例变量,或类没有变量,监视器就什么也不监视了。

为了实现上面的说的监视器的互斥性,虚拟机为每一个对象或类都关联了一个锁(也叫隐形锁),这里说明一下,类锁也是通过对象锁来实现的,因为在类加载的时候,JVM会为每一个类创建一个java.lang.Class的一个实例;所以当锁对对象的时候,也就锁住这个类的类对象。

另外,一个线程是可以对一个对象进行多次上锁,也就对应着多次释放;它是通过JVM为每个对象锁提供的lock计算器,上一次锁,就加1,对应的减1,当计算器的值为0时,就释放。这个对象锁是JVM内部的监视器使用的,也是由JVM自动生成的,所有程序猿就不用自己动手来加了。

介绍完java的同步原理后,我们进入正题,先来说说synchronized的使用。

先来运行一个例子试试。

1.packagethread_test;2.3./**4. * 测试扩展Thread类实现的多线程程序

5. *

6. *@authorciding

7. * @createTime Dec 7, 2011 9:37:25 AM

8. *

9.*/10.publicclassTestThreadextendsThread{11.privateintthreadnum;12.13.publicTestThread(intthreadnum) {14.this.threadnum=threadnum;15.    }16.17.    @Override18.publicsynchronizedvoidrun() {19.for(inti=0;i<1000;i++){20.                    System.out.println("NO."+threadnum+":"+i );21.        }22.        }23.24.publicstaticvoidmain(String[] args)throwsException {25.for(inti=0; i<10; i++){26.newTestThread(i).start();27.                    Thread.sleep(1);28.            }29.        }30.}

运行结果:

1.NO.0:8872.NO.0:8883.NO.0:8894.NO.0:8905.NO.0:8916.NO.0:8927.NO.0:8938.NO.0:8949.NO.7:12210.NO.7:12311.NO.7:124

上面只是一个片段,说明一个问题而已。

细心的童鞋会发现,NO.0:894后面是NO.7:122,也就是说没有按照从0开始到999。

都说synchronized可以实现同步方法或同步块,这里怎么就不行呢?

先从同步的机制来分析一下,同步是通过锁来实现的,那么上面的例子中,锁定了什么对象,或锁定了什么类呢?里面有两个变量,一个是i,一个是threadnum;i是方法内部的,threadnum是私有的。

再来了解一下synchronized的运行机制:

在java程序中,当使用synchronized块或synchronized方法时,标志这个区域进行监视;而JVM在处理程序时,当有程序进入监视区域时,就会自动锁上对象或类。

那么上面的例子中,synchronized关键字用上后,锁定的是什么呢?

当synchronized方法时,锁定调用方法的实例对象本身做为对象锁。本例中,10个线程都有自己创建的TestThread的类对象,所以获取的对象锁,也是自己的对象锁,与其它线程没有任何关系。

要实现方法锁定,必须锁定有共享的对象。

对上面的实例修改一下,再看看:

1.packagethread_test;2.3./**4. * 测试扩展Thread类实现的多线程程序

5. *

6. *@authorciding

7. * @createTime Dec 7, 2011 9:37:25 AM

8. *

9.*/10.publicclassTestThreadextendsThread{11.privateintthreadnum;12.privateString flag;//标记13.14.publicTestThread(intthreadnum,String flag) {15.this.threadnum=threadnum;16.this.flag=flag;17.        }18.19.    @Override20.publicvoidrun() {21.synchronized(flag){22.for(inti=0;i<1000;i++){23.                            System.out.println("NO."+threadnum+":"+i );24.                    }25.        }26.        }27.28.publicstaticvoidmain(String[] args)throwsException {29.            String flag=newString("flag");30.for(inti=0; i<10; i++){31.newTestThread(i,flag).start();32.                    Thread.sleep(1);33.            }34.        }35.}

也就加了一个共享的标志flag。然后在通过synchronized块,对flag标志进行同步;这就满足了锁定共享对象的条件。

是的,运行结果,已经按顺序来了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值