Java多线程初学者指南(12):使用Synchronized块同步变量

简介:
我们可以通过synchronized 块来同步特定的静态或非静态方法。要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized 块括起来,并将这个类变量作为参数传入synchronized 块。下面的代码 演示了如何同步特定的类方法:

   001    package  mythread;
  
002   
  
003    public   class  SyncThread  extends  Thread
  
004   {
  
005        private   static  String sync  =   "" ;
  
006        private  String methodType  =   "" ;
  
007   
  
008        private   static   void  method(String s)
  
009       {
  
010            synchronized  (sync)
  
011           {
  
012               sync  =  s;
  
013               System.out.println(s);
  
014                while  ( true );
  
015           }
  
016       }
  
017        public   void  method1()
  
018       {
  
019           method( " method1 " );
  
020       }
  
021        public   static   void  staticMethod1()
  
022       {
  
023           method( " staticMethod1 " );
  
024       }
  
025        public   void  run()
  
026       {
  
027            if  (methodType.equals( " static " ))
  
028               staticMethod1();
  
029            else   if  (methodType.equals( " nonstatic " ))
  
030               method1();
  
031       }
  
032        public  SyncThread(String methodType)
  
033       {
  
034            this .methodType  =  methodType;
  
035       }
  
036        public   static   void  main(String[] args)  throws  Exception
  
037       {
  
038            SyncThread  sample1  =   new   SyncThread ( " nonstatic " );
  
039            SyncThread  sample2  =   new   SyncThread ( " static " );
  
040           sample1.start();
  
041           sample2.start();
  
042       }
  
043   }
运行结果如下:
method1
staticMethod1
看到上面的运行结果很多读者可能感到惊奇。在上面的代码中method1 staticMethod1 方法使用了静态字符串变量sync 进行同步。这两个方法只能有一个同时执行,而这两个方法都会执行014 行的无限循环语句。因此,输出结果只能是method1 staticMethod1 其中之一。但这个程序将这两个字符串都输出了。
出现这种结果的愿意很简单,我们看一下012 行就知道了。原来在这一行将sync 的值改变了。在这里要说一下Java 中的String 类型。String 类型和Java 中其他的复杂类型不同。在使用String 型变量时,只要给这个变量赋一次值,Java 就会创建个新的String 类型的实例。如下面的代码所示:
String s  =   " hello " ;
System.out.println(s.hashCode());
=   " world " ;
System.out.println(s.hashCode());  
在上面的代码中。第一个s 和再次赋值后的s hashCode 的值是不一样的。由于创建String 类的实例并不需要使用new ,因此,在同步String 类型的变量时要注意不要给这个变量赋值,否则会使变量无法同步。
由于在012 行已经为sync 创建了一个新的实例,假设method1 先执行,当method1 方法执行了013 行的代码后,sync 的值就已经不是最初那个值了,而method1 方法锁定的仍然是sync 变量最初的那个值。而在这时,staticMethod1 正好执行到synchronized(sync) ,在staticMethod1 方法中要锁定的这个sync method1 方法锁定的sync 已经不是一个了,因此,这两个方法的同步性已经被破坏了。
解决以上问题的方法当然是将012 行去掉。在本例中加上这行,只是为了说明使用类变量来同步方法时如果在synchronized 块中将同步变量的值改变,就会破坏方法之间的同步。为了彻底避免这种情况发生,在定义同步变量时可以使用final 关键字。如将上面的程序中的005 行可改成如下形式:
private   final   static  String sync  =   "" ;
    使用final 关键字后,sync 只能在定义时为其赋值,并且以后不能再修改。如果在程序的其他地方给sync 赋了值,程序就无法编译通过。在Eclipse 等开发工具中,会直接在错误的地方给出提示。
    我们可以从两个角度来理解synchronized 块。如果从类方法的角度来理解,可以通过类变量来同步相应的方法。如果从类变量的角度来理解,可以使用synchronized 块来保证某个类变量同时只能被一个方法访问。不管从哪个角度来理解,它们的实质都是一样的,就是利用类变量来获得同步锁,通过同步锁的互斥性来实现同步。
注意:在使用 synchronized 块时应注意, synchronized 块只能使用对象作为它的参数。如果是简单类型的变量 ( int char boolean ) ,不能使用 synchronized 来同步。
 


 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/214823,如需转载请自行联系原作者

相关文章
|
1天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
1天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
|
1天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
2天前
|
缓存 分布式计算 监控
Java并发编程:深入理解线程池
【4月更文挑战第17天】在Java并发编程中,线程池是一种非常重要的技术,它可以有效地管理和控制线程的执行,提高系统的性能和稳定性。本文将深入探讨Java线程池的工作原理,使用方法以及在实际开发中的应用场景,帮助读者更好地理解和使用Java线程池。
|
2天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
9 1
|
2天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
2 0
|
Java
java中同步嵌套引起的死锁事例代码
/* 目的:自己写一个由于同步嵌套引起的死锁! 思路:多个线程在执行时,某一时刻,0-Thread绑定了LockA锁,1-Thread绑定了LockB锁! 当0-Thread要去绑定LockB锁时 和 1-Thread要去绑定LockA锁时都不能绑定,此时两个线程不能继续进行! *...
502 0
|
9天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。

热门文章

最新文章