`
sunnylocus
  • 浏览: 876732 次
  • 性别: Icon_minigender_1
  • 来自: 美国图森
社区版块
存档分类
最新评论

synchronized方法验证,不要被谬论迷惑

    博客分类:
  • Java
阅读更多

       以前编程没有怎么接触过synchronized方法,不太了解,今天编程遇到了多个线程访问同一个共享资源的问题,google了下synchronized使用方法,网上有二种说法,第一种说法是当一个线程访问了某个对象中的synchronzied方法,其它线程可以继续访问其它的synchronized方法,第二个说法与第一种说法相反,不能访问。搞的我也不确定,更要命的是,这两种说法在网上一边又一边的转载,以讹传讹,要误导不少java新手。到底那一个是正确的,编个程序验证就清楚了

   下面是一个示例程序,有三个角色,一个家庭中的父亲,母亲,和儿子,同时在ATM取款机上向同一个银行账号进行取钱和查询的操作
1.银行类

  

package com.sunnylocus.test;

public class Bank  {
	private int money = 100;
	//取钱
	public synchronized void takeMoney(int num) {
			Thread.sleep(1000 * 5);   //取钱需要5秒
			money -= num;
	}
	//存钱
	public synchronized void addMoney(int num) {
			Thread.sleep(1000 * 10); //存钱需要10秒
			money += money;
	}
	//查询
	public int queryMoney() {
		return money;
	}
}

 

 


2.父亲类

package com.sunnylocus.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Father extends Thread{
	private Bank bank;
	private int num;
	
	DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss");  //日期格式对象
	
	public Father(Bank bank,int num) {
		this.bank = bank;
		this.num = num;
	}

	public void run() {
		System.out.println("老爸正在取钱...      --"+dateFormate.format(new Date()));
		bank.takeMoney(num);
		System.out.println("老爸取走了"+num +"         --"+dateFormate.format(new Date()));
	}
	
}



3.母亲类

package com.sunnylocus.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Monther extends Thread{
	private Bank bank;
	private int num;
	DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss");  //日期格式对象
	
	public Monther(Bank bank,int num) {
		this.bank = bank;
		this.num = num;
	}

	public void run() {
		System.out.println("老妈正在取钱....         "+dateFormate.format(new Date()));
		bank.takeMoney(num);
		System.out.println("老妈取走了"+num+"         --"+dateFormate.format(new Date()));
	}
	
}



4.儿子类

package com.sunnylocus.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Sun extends Thread{
	private Bank bank;
	DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss");  //日期格式对象
	public Sun(Bank bank) {
		this.bank = bank;
	}

	public void run() {
		//查询余款
		System.out.println("儿子查询余额:"+bank.queryMoney() +"     --"+dateFormate.format(new Date()));
	}
}



5.测试类

package com.sunnylocus.test;

public class Main {
	public static void main(String[] args) {
		//银行
		Bank bank = new Bank();
		//老爸
		Father father = new Father(bank,50);
		//老妈
		Monther monther = new Monther(bank,100);
		//儿子
		Sun sun = new Sun(bank);
		
		new Thread(father).start();
		new Thread(monther).start();
		new Thread(sun).start();
		
	}
}


输出结果:

老爸正在取钱...               --上午 11:52:01
老妈正在取钱....              --上午 11:52:01
儿子查询余额:100           --上午 11:52:01

老爸取走了50                 --上午 11:52:06
老妈取了30                    --上午 11:52:11


   一共有三个线程,同时启动,父亲线程和母亲线程同时取款的操作,因为父亲线程已经占用了对象锁,所以母亲线程只能等到父亲执行完方法释放锁后,才能执行。即便父亲线程占用了对象锁,儿子线程也能调用非synchronzied方法
 

     我们把母亲类的取钱的方法改成存钱的操作,虽然不是同一个synchronized方法.也一样不能执行,必须等到父亲线程方法执行完毕后,才能进行存钱的操作

我的结论: 
     synchronized method(){}可以防止多个线程同时访问这个对象的synchronized方法,如果一个对象有多个synchronized方法,只要一个线 程访问了其中的一个synchronized方法且没有释放对象锁,那么其它线程不能同时访问这个对象中的任何一个synchronized方法,但可以访问这个对象中的非synchronized方法。

 

5
2
分享到:
评论
6 楼 sunnylocus 2011-07-21  
seablue_xj 写道
public synchronized void get1() {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println("get1");
}

public synchronized void get2() {
System.out.println("get2");
this.notify();
}

请问下,如果按照博主的结论,两个线程,一个调get1,另一个调get2会有什么结果?
一个线程占着get1而另一个线程不能访问get2?
如果这样,那get1中的wait()该怎么解锁?

请楼主好好检查自己的代码。谢谢

估计这个兄弟被自己的代码给迷惑了,你的意思是:我既然调用了get1,那么get2就不能执行了,因为它们都是 synchronized方法。ok,那咱们来分析下:
1、首先你启动了一个线程去调用get1方法,因为get1方法用synchronized修饰,所以该方法获得当前的对象锁 (只要持有对象锁且没有释放,那么其它线线程无法调用其它的Synchronized方法)
2、在get1方法里,你调用了this.wait(),将当前线程挂起。问题出在这里,wait方法除了将线程挂起外,还释放了它占有的对象锁。
3、你又启了一个线程去调用get2()方法,此时的对象锁已经通过wait方法释放掉了,它当然能执行get2方法了。执行notify后将唤醒阻塞在get1方法里的线程,get1会继续执行wait后面的代码。
还有什么问题吗?
5 楼 seablue_xj 2011-07-20  
public synchronized void get1() {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println("get1");
}

public synchronized void get2() {
System.out.println("get2");
this.notify();
}

请问下,如果按照博主的结论,两个线程,一个调get1,另一个调get2会有什么结果?
一个线程占着get1而另一个线程不能访问get2?
如果这样,那get1中的wait()该怎么解锁?

请楼主好好检查自己的代码。谢谢
4 楼 roheven 2008-10-17  
明白了synchronized 方法 实际上是 synchronized(this),就知道结论是什么了
3 楼 soartju 2008-08-29  
恩,这个结论我认同。
如果再加上类锁的概念就更好了。
2 楼 zidane0207 2008-08-29  
很好的学习例子
1 楼 congpeixue 2008-08-02  
可以深入浅出了

相关推荐

    java里面synchronized用法.doc

    1. 对象实例范围:synchronized 关键字可以被用于对象实例的方法上,以防止多个线程同时访问同一个对象的 synchronized 方法。例如: ```java public class MyClass { public synchronized void myMethod() { // ....

    java锁机制Synchronizedjava锁机制Synchronized

    这些房间可以被分为两种:上锁房间(synchronized 方法)和不上锁房间(普通方法)。每个对象都有一个钥匙(key),该钥匙可以打开所有上锁的房间。 Synchronized 方法 当一个线程想要进入一个上锁房间时,它需要...

    java中synchronized用法

    当 synchronized 关键字加在方法上时,它锁定的是调用这个同步方法的对象。例如,在以下代码中: public synchronized void methodAAA(){ //…. } 这个方法是同步方法,它锁定的是调用这个方法的对象,如 P1。当...

    浅谈synchronized方法对非synchronized方法的影响

    在Java中,synchronized关键字是用来实现线程同步的,它可以保证在多线程环境中,某个方法或代码块只能被一个线程访问。今天,我们来探讨synchronized方法对非synchronized方法的影响。 首先,我们来看一个例子。...

    synchronized的几种示例

    在这个例子中,`increment()`方法被`synchronized`修饰,意味着每次只有一个线程可以调用此方法,防止了多个线程同时修改`count`导致的数据不一致问题。 2. **代码块加锁(this)** 如果只希望锁定代码块而非整个...

    volatile和synchronized的区别

    - **原子性**:`synchronized`保证了在执行代码块或方法时的原子性,这意味着整个代码块或方法要么全部被执行,要么全部不被执行。 ##### 2. volatile关键字 `volatile`关键字用于标记那些在多线程环境中可能会被...

    [JAVA][synchronized的使用]

    例如,创建两个线程,分别访问一个共享的`synchronized`方法,观察其执行顺序和结果,以此验证同步的效果。 总结,`synchronized`是Java中实现线程安全的关键工具,理解其工作原理和使用方式对于编写高效、安全的多...

    Android synchronized 测试案例

    当一个线程进入`synchronized`代码块或方法时,其他试图进入同一块的线程将被阻塞,直到持有锁的线程退出。 二、同步单个对象 1. 同步方法:在方法声明前加上`synchronized`关键字,使得每次只有一个线程能执行该...

    synchronized并发讲解源码.zip

    当一个方法被`synchronized`修饰时,同一时间只能有一个线程访问该方法,其他试图访问的线程会被阻塞,直到当前线程执行完毕。这种方式保证了同一对象的同步访问。 1. **同步实例方法**: ```java public class ...

    synchronized用法大全实例

    在这个例子中,`increment`和`decrement`方法都被声明为同步,这意味着它们在同一时刻只能被一个线程访问,避免了并发计数的不一致性。 ### 2. 同步语句块 同步语句块允许我们对特定代码块进行同步,其语法结构...

    Java synchronized使用案例

    1. **方法同步**:在方法声明前加上`synchronized`,整个方法都会被锁定,任何时刻只有一个线程能执行该方法。 ```java public synchronized void method() { // 方法体 } ``` 2. **代码块同步**:锁定特定对象,...

    Synchronized关键字的用法

    - **实例方法**:可以直接将`synchronized`关键字放在实例方法前,此时该方法的锁为当前对象实例本身。 ```java public synchronized void method() { // 同步方法体 } ``` - 当一个线程调用此方法时,会锁定...

    java synchronized 学习

    多个线程访问同一个对象的任意 synchronized 修饰的方法或代码块,只要有一个线程拥有了 synchronized 同步锁,其他线程不管想访问 synchronized 修饰的哪个方法或代码块,同样也会被阻塞。 通过使用 synchronized ...

    java_synchronized详解

    通过在方法或代码块上使用`synchronized`,可以确保同一时间只有一个线程能访问这些代码区域,从而有效避免了多线程环境下的数据竞争和不一致性问题。 #### 二、synchronized的作用机制 `synchronized`主要通过对象...

    JAVA synchronized详解

    在这个类中,`run()`方法被`synchronized`修饰,这意味着同一时间只能有一个线程执行这段代码。 ```java public class Thread1 implements Runnable { @Override public void run() { synchronized (this) { ...

    synchronized关键字的用法详解

    这里,`accessVal`方法被声明为`synchronized`。这意味着每次只有一个线程可以执行该方法。当一个线程正在执行该方法时,其他试图调用该方法的线程将被阻塞,直到当前线程完成方法的执行并释放锁。 ##### 2. ...

    synchronized详解

    - **可重入性**:Java的`synchronized`是可重入的,意味着一个线程在拥有锁的情况下可以再次请求该锁而不会被阻塞。 - **避免锁竞争**:尽量减少多个线程对同一资源的并发访问,可以通过使用并发集合类如`...

    java synchronized详解

    Java的`synchronized`具备可重入性,即一个线程已经获得了某个对象的锁,那么它可以再次请求这个锁(递归调用同步方法)而不被阻塞。 8. **监视器等待与唤醒** 通过`wait()`、`notify()`和`notifyAll()`方法,线程...

    Java使用synchronized修饰方法来同步线程的实例演示

    其他尝试进入相同代码块或方法的线程将被阻塞,直到当前线程执行完毕并释放锁。这样可以确保在任何给定时刻,只有一个线程能够执行特定的同步代码。 2. **synchronized的两种用法** - **synchronized方法**:在...

    synchronized关键字的实质及用法

    - **方法同步**:在方法声明前加上`synchronized`关键字,这将使得整个方法成为同步方法,每次只有一个线程可以执行该方法。 ```java public synchronized void someMethod() { // ... } ``` - **代码块...

Global site tag (gtag.js) - Google Analytics