快捷搜索:

Java 多线程同步问题的探究(二、给我一把锁,我

在上一篇中,我们讲到了多线程是若何处置惩罚共享资本的,以及包管他们对资本进行互斥造访所依附的紧张机制:工具锁。

本篇中,我们来看一看传统的同步实现要领以及这背后的道理。

很多人都知道,在Java多线程编程中,有一个紧张的关键字,synchronized。然则很多人看到这个器械会认为利诱:“都说同步机制是经由过程工具锁来实现的,然则这么一个关键字,我也看不出来Java法度榜样锁住了哪个工具阿?“

没错,我一开始也是对这个问题认为利诱和不解。不过还好,我们有下面的这个例程:

1 public class ThreadTest extends Thread {

2

3     private int threadNo;

4

5     public ThreadTest(int threadNo) {

6         this.threadNo = threadNo;

7     }

8

9     public static void main(String[] args) throws Exception {

10         for (int i = 1; i

这个法度榜样着实便是让10个线程在节制台上数数,从1数到9999。抱负环境下,我们盼望看到一个线程数完,然后才是另一个线程开始数数。然则这个法度榜样的履行历程奉告我们,这些线程照样乱糟糟的在那里抢着报数,涓滴没有任何规矩可言。

然则细心的读者留意到:run措施照样加了一个synchronized关键字的,按事理说,这些线程应该可以一个接一个的履行这个run措施才对阿。

然则经由过程上一篇中,我们提到的,对付一个成员措施加synchronized关键字,这实际上因此这个成员措施所在的工具本身作为工具锁。在本例中,便因此ThreadTest类的一个详细工具,也便是该线程自身作为工具锁的。一共十个线程,每个线程持有自己线程工具的那个工具锁。这一定不能孕育发生同步的效果。换句话说,假如要对这些线程进行同步,那么这些线程所持有的工具锁该当是共享且独一的!

我们来看下面的例程:

1 public class ThreadTest2 extends Thread {

2

3     private int threadNo;

4     private String lock;

5

6     public ThreadTest2(int threadNo, String lock) {

7         this.threadNo = threadNo;

8         this.lock = lock;

9     }

10

11     public static void main(String[] args) throws Exception {

12         String lock = new String("lock");

13         for (int i = 1; i

我们留意到,该法度榜样经由过程在main措施启动10个线程之前,创建了一个String类型的工具。并经由过程ThreadTest2的构造函数,将这个工具赋值给每一个ThreadTest2线程工具中的私有变量lock。根据Java措施的传值特征,我们知道,这些线程的lock变量实际上指向的是堆内存中的同一个区域,即寄放main函数中的lock变量的区域。

法度榜样将原本run措施前的synchronized关键字去掉落,换用了run措施中的一个synchronized块来实现。这个同步块的工具锁,便是 main措施中创建的那个String工具。换句话说,他们指向的是同一个String类型的工具,工具锁是共享且独一的!

于是,我们看到了预期的效果:10个线程不再是争先恐后的报数了,而是一个接一个的报数。

再来看下面的例程:

1 public class ThreadTest3 extends Thread {

2

3     private int threadNo;

4     private String lock;

5

6     public ThreadTest3(int threadNo) {

7         this.threadNo = threadNo;

8     }

9

10     public static void main(String[] args) throws Exception {

11         //String lock = new String("lock");

12         for (int i = 1; i

细心的读者发清楚明了:这段代码没有应用main措施中创建的String工具作为这10个线程的线程锁。而是经由过程在run措施中调用本线程中一个静态的同步措施abc而实现了线程的同步。我想看到这里,你们应该很利诱:这里synchronized静态措施是用什么来做工具锁的呢?

我们知道,对付同步静态措施,工具锁便是该静态放发所在的类的Class实例,因为在JVM中,所有被加载的类都有独一的类工具,详细到本例,便是独一的ThreadTest3.class工具。不管我们创建了该类的若干实例,然则它的类实例仍旧是一个!

这样我们就知道了:

1、对付同步的措施或者代码块来说,必须得到工具锁才能够进入同步措施或者代码块进行操作;

2、假如采纳method级其余同步,则工具锁即为method所在的工具,假如是静态措施,工具锁即指method所在的

Class工具(独一);

3、对付代码块,工具锁即指synchronized(abc)中的abc;

4、由于第一种环境,工具锁即为每一个线程工具,是以有多个,以是同步掉效,第二种共用同一个工具锁lock,是以同步生效,第三个由于是

static是以工具锁为ThreadTest3的class 工具,是以同步生效。

如上述精确,则同步有两种要领,同步块和同步措施(为什么没有wait和notify?这个我会在弥补章节中做出阐述)

假如是同步代码块,则工具锁必要编程职员自己指定,一样平常有些代码为synchronized(this)只有在单态模式才生效;

(本类的实例有且只有一个)

假如是同步措施,则分静态和非静态两种。

静态措施则必然会同步,非静态措施需在单例模式才生效,保举用静态措施(不用担心是否单例)。

以是说,在Java多线程编程中,最常见的synchronized关键字实际上是寄托工具锁的机制来实现线程同步的。

我们彷佛可以听到synchronized在向我们说:“给我一把锁,我能创造一个规矩”。

下一篇中,我们将看到JDK 5供给的新的同步机制,也便是大年夜名鼎鼎的Doug Lee供给的Java Concurrency框架。

您可能还会对下面的文章感兴趣: