要想解决“脏数据”的问题,最简单的方法就是使用synchronized关键字来使run方法同步,代码如下:
publicsynchronizedvoidrun()
{
}
从上面的代码可以看出,只要在void和public之间加上synchronized关键字,就可以使run方法同步,也就是说,对于同一个Java类的对象实例,run方法同时只能被一个线程调用,并当前的run执行完后,才能被其他的线程调用。即使当前线程执行到了run方法中的yield方法,也只是暂停了一下。由于其他线程无法执行run方法,因此,最终还是会由当前的线程来继续执行。先看看下面的代码:
sychronized关键字只和一个对象实例绑定
classTest
{
publicsynchronizedvoidmethod()
{
}
}
publicclassSyncimplementsRunnable
{
privateTesttest;
publicvoidrun()
{
test.method();
}
publicSync(Testtest)
{
this.test=test;
}
publicstaticvoidmain(String[]args)throwsException
{
Testtest1=newTest();
Testtest2=newTest();
Syncsync1=newSync(test1);
Syncsync2=newSync(test2);
newThread(sync1).start();
newThread(sync2).start();
}
}
在Test类中的method方法是同步的。但上面的代码建立了两个Test类的实例,因此,test1和test2的method方法是分别执行的。要想让method同步,必须在建立Sync类的实例时向它的构造方法中传入同一个Test类的实例,如下面的代码所示:
Syncsync1=newSync(test1);
不仅可以使用synchronized来同步非静态方法,也可以使用synchronized来同步静态方法。如可以按如下方式来定义method方法:
classTest
{
publicstaticsynchronizedvoidmethod(){}
}
建立Test类的对象实例如下:
Testtest=newTest();
对于静态方法来说,只要加上了synchronized关键字,这个方法就是同步的,无论是使用test.method(),还是使用Test.method()来调用method方法,method都是同步的,并不存在非静态方法的多个实例的问题。
在23种设计模式中的单件(Singleton)模式如果按传统的方法设计,也是线程不安全的,下面的代码是一个线程不安全的单件模式。
packagetest;
//线程安全的Singleton模式
classSingleton
{
privatestaticSingletonsample;
privateSingleton()
{
}
publicstaticSingletongetInstance()
{
if(sample==null)
{
Thread.yield();//为了放大Singleton模式的线程不安全性
sample=newSingleton();
}
returnsample;
}
}
publicclassMyThreadextendsThread
{
publicvoidrun()
{
Singletonsingleton=Singleton.getInstance();
System.out.println(singleton.hashCode());
}
publicstaticvoidmain(String[]args)
{
Threadthreads[]=newThread[5];
for(inti=0;i<threads.length;i++)
threads[i]=newMyThread();
for(inti=0;i<threads.length;i++)
threads[i].start();
}
}
在上面的代码调用yield方法是为了使单件模式的线程不安全性表现出来,如果将这行去掉,上面的实现仍然是线程不安全的,只是出现的可能性小得多。
程序的运行结果如下:
25358555
26399554
7051261
29855319
5383406
上面的运行结果可能在不同的运行环境上有所有同,但一般这五行输出不会完全相同。从这个输出结果可以看出,通过getInstance方法得到的对象实例是五个,而不是我们期望的一个。这是因为当一个线程执行了Thread.yield()后,就将CPU资源交给了另外一个线程。由于在线程之间切换时并未执行到创建Singleton对象实例的语句,因此,这几个线程都通过了if判断,所以,就会产生了建立五个对象实例的情况(可能创建的是四个或三个对象实例,这取决于有多少个线程在创建Singleton对象之前通过了if判断,每次运行时可能结果会不一样)。
要想使上面的单件模式变成线程安全的,只要为getInstance加上synchronized关键字即可。代码如下:
publicstaticsynchronizedSingletongetInstance(){}
当然,还有更简单的方法,就是在定义Singleton变量时就建立Singleton对象,代码如下:
privatestaticfinalSingletonsample=newSingleton();
然后在getInstance方法中直接将sample返回即可。这种方式虽然简单,但不知在getInstance方法中创建Singleton对象灵活。读者可以根据具体的需求选择使用不同的方法来实现单件模式。
在使用synchronized关键字时有以下四点需要注意:
1. synchronized关键字不能继承。
虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字
classParent
{
publicsynchronizedvoidmethod(){}
}
classChildextendsParent
{
publicsynchronizedvoidmethod(){}
}
在子类方法中调用父类的同步方法
classParent
{
publicsynchronizedvoidmethod(){}
}
classChildextendsParent
{
publicvoidmethod(){super.method();}
}
2. 在定义接口方法时不能使用synchronized关键字。
3. 构造方法不能使用synchronized关键字,但可以使用下节要讨论的synchronized块来进行同步。
4. synchronized可以自由放置。
在前面的例子中使用都是将synchronized关键字放在方法的返回类型前面。但这并不是synchronized可放置唯一位置。在非静态方法中,synchronized还可以放在方法定义的最前面,在静态方法中,synchronized可以放在static的前面,代码如下:
publicsynchronizedvoidmethod();
synchronizedpublicvoidmethod();
publicstaticsynchronizedvoidmethod();
publicsynchronizedstaticvoidmethod();
synchronizedpublicstaticvoidmethod();
但要注意,synchronized不能放在方法返回类型的后面,如下面的代码是错误的:
publicvoidsynchronizedmethod();
publicstaticvoidsynchronizedmethod();
synchronized关键字只能用来同步方法,不能用来同步类变量,如下面的代码也是错误的。
publicsynchronizedintn=0;
publicstaticsynchronizedintn=0;
虽然使用synchronized关键字同步方法是最安全的同步方式,但大量使用synchronized关键字会造成不必要的资源消耗以及性能损失。虽然从表面上看synchronized锁定的是一个方法,但实际上synchronized锁定的是一个类。也就是说,如果在非静态方法method1和method2定义时都使用了synchronized,在method1未执行完之前,method2是不能执行的。静态方法和非静态方法的情况类似。但静态和非静态方法不会互相影响。看看如下的代码:
packagetest;
publicclassMyThread1extendsThread
{
publicStringmethodName;
publicstaticvoidmethod(Strings)
{
System.out.println(s);
while(true)
;
}
publicsynchronizedvoidmethod1()
{
method("非静态的method1方法");
}
publicsynchronizedvoidmethod2()
{
method("非静态的method2方法");
}
publicstaticsynchronizedvoidmethod3()
{
method("静态的method3方法");
}
publicstaticsynchronizedvoidmethod4()
{
method("静态的method4方法");
}
publicvoidrun()
{
try
{
getClass().getMethod(methodName).invoke(this);
}
catch(Exceptione)
{
}
}
publicstaticvoidmain(String[]args)throwsException
{
MyThread1myThread1=newMyThread1();
for(inti=1;i<=4;i++)
{
myThread1.methodName="method"+String.valueOf(i);
newThread(myThread1).start();
sleep(100);
}
}
}
运行结果如下:
非静态的method1方法
静态的method3方法
从上面的运行结果可以看出,
method2
和
method4
在
method1
和
method3
未结束之前不能运行。因此,我们可以得出一个结论,如果在类中使用
synchronized
关键字来定义非静态方法,那将影响这个中的所有使用
synchronized
关键字定义的非静态方法。如果定义的是静态方法,那么将影响类中所有使用
synchronized
关键字定义的静态方法。这有点象数据表中的表锁,当修改一条记录时,系统就将整个表都锁住了,因此,大量使用这种同步方式会使程序的性能大幅度下降。
分享到:
相关推荐
Java 线程同步机制中 synchronized 关键字的理解 Java 的线程同步机制是为了解决多个线程共享同一片存储空间所带来的访问冲突问题。其中,synchronized 关键字是 Java 语言中解决这种冲突的重要机制。 ...
Java中的`synchronized`...总之,`synchronized`关键字在Java多线程编程中扮演着关键角色,确保了共享资源的安全访问,避免了竞态条件和数据不一致。理解和熟练运用`synchronized`对于编写健壮的并发程序至关重要。
在多线程编程中,确保线程安全是至关重要的。Java提供了多种机制来处理并发问题,其中synchronized...通过深入理解synchronized关键字,开发者可以更好地处理Java中的并发问题,构建出更加健壮和高效的多线程应用程序。
本教程将深入讲解`synchronized`关键字及其在Java多线程中的应用。 一、synchronized关键字的作用与原理 `synchronized`关键字主要有两个作用:同步方法和同步块。它通过锁机制来实现线程同步,防止多个线程同时...
总结来说,`synchronized`关键字在Java多线程编程中扮演着关键角色,确保了线程安全和数据一致性。然而,正确理解和使用它是至关重要的,避免滥用并结合其他并发控制手段,才能编写出高效且健壮的多线程程序。在实际...
在这个方法中,synchronized 关键字锁住了整个类,这样可以确保多线程环境下的线程平安。 synchronized 关键字是 Java 中解决线程同步问题的重要工具,但是需要正确的用法,否则将无法实现线程平安。在编写代码时,...
Java 多线程与并发中的 synchronized 关键字是实现同步块的互斥访问和线程的阻塞及唤醒等工作的重要工具。下面将对 synchronized 关键字进行详细分析。 synchronized 关键字的使用场景 synchronized 关键字可以...
在Java多线程编程中,`synchronized`关键字是一个至关重要的工具,用于处理并发访问时可能出现的数据一致性问题,也就是防止“脏数据”问题。当多个线程试图访问和修改同一块共享资源时,如果不加控制,可能会导致...
本文深入探讨了Java中用于解决并发...通过对synchronized关键字的深入分析,本文为Java开发者提供了对并发编程中关键同步工具的全面理解,特别是在高并发场景下如何有效使用synchronized以确保线程安全和提高程序性能。
Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用synchronized关键字还不能...
Synchronized 关键字是 Java 并发编程中最基本的同步机制,它可以保证线程安全,包括原子性、可见性和有序性。Synchronized 关键字可以修饰方法或代码块,使得在同一时刻只有一个线程可以执行该方法或代码块,从而...
Java中的多线程同步是通过对象锁机制来实现的,synchronized关键字正是这一机制的关键。它确保了在任何时刻,只有一个线程能够访问特定的共享资源,从而避免数据不一致的问题。本文将详细讲解Java线程的基本概念、...
通过上述分析可以看出,`synchronized`关键字是Java多线程编程中不可或缺的一部分。它不仅提供了一种简单有效的同步机制,还具备自动解锁和可重入等高级特性,使得开发人员能够轻松地编写出高效且可靠的多线程程序。...
Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源,以避免数据不一致和竞态条件。在这个问题中,我们将深入理解`synchronized`的关键字用法,包括同步方法和同步块。 1. **...
标题中的"java 多线程synchronized互斥锁demo"指的是一个示例,展示了如何在多线程环境下使用`synchronized`关键字创建互斥锁,确保同一时间只有一个线程可以访问特定的代码块或方法。 描述中的"一个多线程访问的同...
Java中的`synchronized`关键字是用于实现线程同步的关键机制,它的主要目的是确保在多线程环境中,对共享资源的访问能够保持数据的一致性和完整性。本文将深入探讨`synchronized`的两种主要用法:synchronized方法和...
Java多线程同步机制的应用分析是指在Java语言中,如何使用同步机制来保护临界区,以避免多线程之间的冲突和错误。该机制通过管程机制和同步语法来保护临界区,使得多线程可以安全、高效地运行。 在多线程编程中,...
本文将探讨Synchronized关键字在解决并发控制中的作用及其使用方式。 首先,让我们回顾一下问题的背景:在给出的示例代码中,创建了10个线程,每个线程都对共享变量`count`进行10000000次的累加操作。理论上,最终...
在Java编程中,`synchronized`关键字是用来解决多线程环境下的线程安全问题的关键工具。线程安全意味着当多个线程访问同一段代码时,该代码能够正确地处理并发情况,不会出现数据不一致或者资源竞争的问题。本文将...