以前编程没有怎么接触过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方法。
分享到:
相关推荐
1. 对象实例范围:synchronized 关键字可以被用于对象实例的方法上,以防止多个线程同时访问同一个对象的 synchronized 方法。例如: ```java public class MyClass { public synchronized void myMethod() { // ....
这些房间可以被分为两种:上锁房间(synchronized 方法)和不上锁房间(普通方法)。每个对象都有一个钥匙(key),该钥匙可以打开所有上锁的房间。 Synchronized 方法 当一个线程想要进入一个上锁房间时,它需要...
当 synchronized 关键字加在方法上时,它锁定的是调用这个同步方法的对象。例如,在以下代码中: public synchronized void methodAAA(){ //…. } 这个方法是同步方法,它锁定的是调用这个方法的对象,如 P1。当...
在Java中,synchronized关键字是用来实现线程同步的,它可以保证在多线程环境中,某个方法或代码块只能被一个线程访问。今天,我们来探讨synchronized方法对非synchronized方法的影响。 首先,我们来看一个例子。...
在这个例子中,`increment()`方法被`synchronized`修饰,意味着每次只有一个线程可以调用此方法,防止了多个线程同时修改`count`导致的数据不一致问题。 2. **代码块加锁(this)** 如果只希望锁定代码块而非整个...
- **原子性**:`synchronized`保证了在执行代码块或方法时的原子性,这意味着整个代码块或方法要么全部被执行,要么全部不被执行。 ##### 2. volatile关键字 `volatile`关键字用于标记那些在多线程环境中可能会被...
例如,创建两个线程,分别访问一个共享的`synchronized`方法,观察其执行顺序和结果,以此验证同步的效果。 总结,`synchronized`是Java中实现线程安全的关键工具,理解其工作原理和使用方式对于编写高效、安全的多...
当一个线程进入`synchronized`代码块或方法时,其他试图进入同一块的线程将被阻塞,直到持有锁的线程退出。 二、同步单个对象 1. 同步方法:在方法声明前加上`synchronized`关键字,使得每次只有一个线程能执行该...
当一个方法被`synchronized`修饰时,同一时间只能有一个线程访问该方法,其他试图访问的线程会被阻塞,直到当前线程执行完毕。这种方式保证了同一对象的同步访问。 1. **同步实例方法**: ```java public class ...
在这个例子中,`increment`和`decrement`方法都被声明为同步,这意味着它们在同一时刻只能被一个线程访问,避免了并发计数的不一致性。 ### 2. 同步语句块 同步语句块允许我们对特定代码块进行同步,其语法结构...
1. **方法同步**:在方法声明前加上`synchronized`,整个方法都会被锁定,任何时刻只有一个线程能执行该方法。 ```java public synchronized void method() { // 方法体 } ``` 2. **代码块同步**:锁定特定对象,...
- **实例方法**:可以直接将`synchronized`关键字放在实例方法前,此时该方法的锁为当前对象实例本身。 ```java public synchronized void method() { // 同步方法体 } ``` - 当一个线程调用此方法时,会锁定...
多个线程访问同一个对象的任意 synchronized 修饰的方法或代码块,只要有一个线程拥有了 synchronized 同步锁,其他线程不管想访问 synchronized 修饰的哪个方法或代码块,同样也会被阻塞。 通过使用 synchronized ...
通过在方法或代码块上使用`synchronized`,可以确保同一时间只有一个线程能访问这些代码区域,从而有效避免了多线程环境下的数据竞争和不一致性问题。 #### 二、synchronized的作用机制 `synchronized`主要通过对象...
在这个类中,`run()`方法被`synchronized`修饰,这意味着同一时间只能有一个线程执行这段代码。 ```java public class Thread1 implements Runnable { @Override public void run() { synchronized (this) { ...
这里,`accessVal`方法被声明为`synchronized`。这意味着每次只有一个线程可以执行该方法。当一个线程正在执行该方法时,其他试图调用该方法的线程将被阻塞,直到当前线程完成方法的执行并释放锁。 ##### 2. ...
- **可重入性**:Java的`synchronized`是可重入的,意味着一个线程在拥有锁的情况下可以再次请求该锁而不会被阻塞。 - **避免锁竞争**:尽量减少多个线程对同一资源的并发访问,可以通过使用并发集合类如`...
Java的`synchronized`具备可重入性,即一个线程已经获得了某个对象的锁,那么它可以再次请求这个锁(递归调用同步方法)而不被阻塞。 8. **监视器等待与唤醒** 通过`wait()`、`notify()`和`notifyAll()`方法,线程...
其他尝试进入相同代码块或方法的线程将被阻塞,直到当前线程执行完毕并释放锁。这样可以确保在任何给定时刻,只有一个线程能够执行特定的同步代码。 2. **synchronized的两种用法** - **synchronized方法**:在...
- **方法同步**:在方法声明前加上`synchronized`关键字,这将使得整个方法成为同步方法,每次只有一个线程可以执行该方法。 ```java public synchronized void someMethod() { // ... } ``` - **代码块...