java多线程编程之使用Synchronized块同步变量

下面的代码演示了如何同步特定的类方法:


代码如下:

package mythread;

public class SyncThread extends Thread
{
 private static String sync = "";
 private String methodType = "";

private static void method(String s)
 {
  synchronized (sync)
  {
sync = s;
System.out.println(s);
while (true);
  }
 }
 public void method1()
 {
  method("method1");
 }
 public static void staticMethod1()
 {
  method("staticMethod1");
 }
 public void run()
 {
  if (methodType.equals("static"))
staticMethod1();
  else if (methodType.equals("nonstatic"))
method1();
 }
 public SyncThread(String methodType)
 {
  this.methodType = methodType;
 }
 public static void main(String[] args) throws Exception
 {
  SyncThread sample1 = new SyncThread("nonstatic");
  SyncThread sample2 = new SyncThread("static");
  sample1.start();
  sample2.start();
 }
}

运行结果如下:


代码如下:

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());
s = "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来同步。

(0)

相关推荐

  • 浅谈Java多线程编程中Boolean常量的同步问题

    在JAVA中通过synchronized语句可以实现多线程并发.使用同步代码块,JVM保证同一时间只有一个线程可以拥有某一对象的锁.锁机制实现了多个线程安全地对临界资源进行访问.   同步代码写法如下:   代码1: Object obj = new Object(); ... synchronized(obj) { //TODO: 访问临界资源 } JAVA的多线程总是充满陷阱,如果我们用Boolean作为被同步的对象,可能会出现以下两种情况:   一. 以为对一个对象加锁,实际同步的是不同对

  • java多线程编程之使用Synchronized关键字同步类方法

    复制代码 代码如下: public synchronized void run(){     } 从上面的代码可以看出,只要在void和public之间加上synchronized关键字,就可以使run方法同步,也就是说,对于同一个Java类的对象实例,run方法同时只能被一个线程调用,并当前的run执行完后,才能被其他的线程调用.即使当前线程执行到了run方法中的yield方法,也只是暂停了一下.由于其他线程无法执行run方法,因此,最终还是会由当前的线程来继续执行.先看看下面的代码:sych

  • 五种Java多线程同步的方法

    为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常.举 个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块.假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果 呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚.因此多线程同步就是要解决这个问题. 一.不同步时的代码 Bank.java package threadTe

  • 基于Java回顾之多线程同步的使用详解

    首先阐述什么是同步,不同步有什么问题,然后讨论可以采取哪些措施控制同步,接下来我们会仿照回顾网络通信时那样,构建一个服务器端的"线程池",JDK为我们提供了一个很大的concurrent工具包,最后我们会对里面的内容进行探索. 为什么要线程同步? 说到线程同步,大部分情况下, 我们是在针对"单对象多线程"的情况进行讨论,一般会将其分成两部分,一部分是关于"共享变量",一部分关于"执行步骤". 共享变量 当我们在线程对象(Run

  • Java多线程编程之CountDownLatch同步工具使用实例

    好像倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当到达0时,所有等待者就开始执行. java.util.concurrent.CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.用给定的计数初始化CountDownLatch.由于调用了countDown()方法,所以在当前计数到达零之前,await方法会一直受阻塞.之后,会释放所有等待的线程,await的所有后续调用都将立即返回.这种现

  • java多线程的同步方法实例代码

    java多线程的同步方法实例代码 先看一个段有关银行存钱的代码: class Bank { private int sum; public void add(int num){ sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("total num is : " + sum); } } class Cu

  • java多线程编程之为什么要进行数据同步

    Java中的变量分为两类:局部变量和类变量.局部变量是指在方法内定义的变量,如在run方法中定义的变量.对于这些变量来说,并不存在线程之间共享的问题.因此,它们不需要进行数据同步.类变量是在类中定义的变量,作用域是整个类.这类变量可以被多个线程共享.因此,我们需要对这类变量进行数据同步.数据同步就是指在同一时间,只能由一个线程来访问被同步的类变量,当前线程访问完这些变量后,其他线程才能继续访问.这里说的访问是指有写操作的访问,如果所有访问类变量的线程都是读操作,一般是不需要数据同步的.那么如果不

  • Java 多线程同步 锁机制与synchronized深入解析

    打个比方:一个object就像一个大房子,大门永远打开.房子里有很多房间(也就是方法).这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法).房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间.另外我把所有想调用该对象方法的线程比喻成想进入这房子某个 房间的人.所有的东西就这么多了,下面我们看看这些东西之间如何作用的. 在此我们先来明确一下我们的前提条件.该对象至少有一个synchronized方法,否则这个key还有啥意义.当然也就不会有我们的这个主题了. 一

  • java多线程编程之使用Synchronized块同步变量

    下面的代码演示了如何同步特定的类方法: 复制代码 代码如下: package mythread; public class SyncThread extends Thread{ private static String sync = ""; private String methodType = ""; private static void method(String s) {  synchronized (sync)  {sync = s;System.out

  • java多线程编程之使用Synchronized块同步方法

    synchronized关键字有两种用法.第一种就是在<使用Synchronized关键字同步类方法>一文中所介绍的直接用在方法的定义中.另外一种就是synchronized块.我们不仅可以通过synchronized块来同步一个对象变量.也可以使用synchronized块来同步类中的静态方法和非静态方法.synchronized块的语法如下: 复制代码 代码如下: public void method(){    - -    synchronized(表达式)    {        -

  • java多线程编程必备volatile与synchronized深入理解

    目录 Volatile概述 Synchronized概述 Volatile与Synchronized的区别 使用场景 1 Volatile的使用场景 2 Synchronized的使用场景 注意事项 相关面试问题 Volatile概述 Volatile是Java中的一种轻量级同步机制,用于保证变量的可见性和禁止指令重排.当一个变量被声明为Volatile类型时,任何修改该变量的操作都会立即被所有线程看到.也就是说,Volatile修饰的变量在每次修改时都会强制将修改刷新到主内存中,具有很好的可见

  • java多线程编程学习(线程间通信)

    一.概要 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一.可以说,使线程进行通信后,系统之间的交互性会更强大,在大大提高cpu利用率的同时还会使程序员对各线程任务在处理过程中进行有效的把控和监督. 二.等待/通知机制 1."wait/notify"机制:等待/通知机制,wait使线程暂停运行,而notify 使暂停的线程继续运行.用一个厨师和服务员的交互来说明: (1) 服务员取到菜的时间取决于厨师,所以服务员就有&

  • java多线程编程实例

    一.相关知识: Java多线程程序设计到的知识: (一)对同一个数量进行操作 (二)对同一个对象进行操作 (三)回调方法使用 (四)线程同步,死锁问题 (五)线程通信 等等 二.示例一:三个售票窗口同时出售20张票; 程序分析: 1.票数要使用同一个静态值 2.为保证不会出现卖出同一个票数,要java多线程同步锁. 设计思路: 1.创建一个站台类Station,继承Thread,重写run方法,在run方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完! 2.

  • JAVA多线程编程实例详解

    本文实例讲述了JAVA多线程编程.分享给大家供大家参考,具体如下: 进程是系统进行资源调度和分配的一个独立单位. 进程的特点 独立性:进程是系统中独立存在的实体,拥有自己的独立资源和私有空间.在没有经过进程本身允许的情况下,不能直接访问其他进程. 动态性:进程与程序的区别在于,前者是一个正在系统中活动的指令,而后者仅仅是一个静态的指令集合 并发性:多个进程可以在单个处理器上并发执行,而不受影响. 并发性和并行性的区别: 并行性:在同一时刻,有多条指令在多个处理器上同时执行(多个CPU) 并发性:

  • 浅谈java多线程编程

    一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响应更快 多线程的代价: 1)设计更复杂 虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般都更复杂.在多线程访问共享数据的时候,这部分代码需要特别的注意.线程之间的交互往往非常复杂.不正确的线程同步产生的错误非常难以被发现,并且重现以修复. 2)上下文切换的开销 当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

随机推荐