synchronized同步块实例
在java中,每个对象都包含了一把锁(也叫做“监视器”),它自动成为对象的一部分(不必为此写任何特殊的代码)。在给定时刻,只有一个线程可以拥有一个对象的监视器。
示例:线程1进入withdrawal方法时,获得监视器(加锁);当线程1的方法执行完毕返回时,释放监视器(开锁),线程2的withdrawal方能进入
synchronized:
a. 为了确保在任何时刻一个共享对象只被一个线程使用,必须使用“同步(synchronized)”
b. 有两种方式实现同步
a) 使用同步方法
synchronized void methodA() {}
b) 使用同步块
synchronized(obj) { //obj是被锁定的对象
//要同步的语句
}
c. 用synchronized来标识的块或方法即为监视器监视的部分。只有使用synchronized,才能利用对象的监视器功能
d. 调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized方法,除非第一个方法完成了自已的工作,并解除锁定。因此,一个特定对象的所有synchronized方法都共享着一把锁,而且这把锁能防止多个方法对通用内存同时进行写操作(比如同时有多个线程)【任何一个Object有且仅有一把锁,所以方法级的synchronized会对其它有synchronized的方法也起作用,即运行时,此对象最多只能有一个带有synchronized的方法运行】
e. 每个类也有自已的一把锁(作为类的Class对象的一部分),所以synchronized static方法可在一个类的范围内被相互间锁定起来,防止与static数据的接触
f. 一般情况下,只在方法的层次上使用同步
实例:
package com.bijian.thread; /* * 定义了操作类型和金额 */ public class FinTrans { public static String transName; public static double amount; }
package com.bijian.thread; public class TransThread extends Thread { private FinTrans ft; TransThread(FinTrans ft, String name) { super(name); // Save thread's name this.ft = ft; // Save reference to financial transaction object } public void run() { for (int i = 0; i < 100; i++) { if (getName().equals("Deposit Thread")) { // Start of deposit thread's critical code section // 存款操作(每次存2000元) ft.transName = "Deposit"; try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { } ft.amount = 2000.0; System.out.println(ft.transName + " " + ft.amount); // End of deposit thread's critical code section } else { // Start of withdrawal thread's critical code section // 取款操作(每次取250元) ft.transName = "Withdrawal"; try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { } ft.amount = 250.0; System.out.println(ft.transName + " " + ft.amount); // End of withdrawal thread's critical code section } } } }
package com.bijian.thread; public class NeedForSynchronizationDemo { public static void main(String[] args) { FinTrans ft = new FinTrans(); TransThread tt1 = new TransThread(ft, "Deposit Thread"); TransThread tt2 = new TransThread(ft, "Withdrawal Thread"); tt1.start(); tt2.start(); } }
运行结果:
Withdrawal 250.0 Withdrawal 2000.0 Deposit 250.0 Withdrawal 2000.0 Deposit 250.0 Withdrawal 2000.0 Deposit 250.0 Withdrawal 2000.0 Deposit 250.0 Withdrawal 2000.0 Deposit 250.0 …
发现Withdrawal的操作金额有些变成了2000.0,而Deposit的操作金额有些变成了250.0。
一.同步块解决
修改TransThread类,加上synchronized同步块,如下所示:
package com.bijian.thread; public class TransThread extends Thread { private FinTrans ft; TransThread(FinTrans ft, String name) { super(name); // Save thread's name this.ft = ft; // Save reference to financial transaction object } public void run() { for (int i = 0; i < 100; i++) { if (getName().equals("Deposit Thread")) { synchronized (ft) { ft.transName = "Deposit"; try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { } ft.amount = 2000.0; System.out.println(ft.transName + " " + ft.amount); } } else { synchronized (ft) { ft.transName = "Withdrawal"; try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { } ft.amount = 250.0; System.out.println(ft.transName + " " + ft.amount); } } } } }
运行结果如下所示:
Deposit 2000.0 Deposit 2000.0 Withdrawal 250.0 Withdrawal 250.0 Deposit 2000.0 Deposit 2000.0 Deposit 2000.0 Withdrawal 250.0 Withdrawal 250.0 Deposit 2000.0
二.同步方法解决
按现实中的场景,同步的动作应该放在FinTrans类中,而不应由访问的第三方来控制,因此修改实例如下。
package com.bijian.thread; public class FinTrans { private String transName; private double amount; public synchronized void update(String transName, double amount) { this.transName = transName; this.amount = amount; System.out.println(this.transName + " " + this.amount); } public synchronized void save(double amount) { this.transName = "Withdrawal"; this.amount = amount; System.out.println(this.transName + " " + this.amount); try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public synchronized void take(double amount) { this.transName = "Deposit"; this.amount = amount; System.out.println(this.transName + " " + this.amount); try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package com.bijian.thread; public class TransThread extends Thread { private FinTrans ft; TransThread(FinTrans ft, String name) { super(name); // Save thread's name this.ft = ft; // Save reference to financial transaction object } public void run() { for (int i = 0; i < 100; i++) if (getName().equals("Deposit Thread")) ft.take(2000.0); else ft.save(250.0); } }
运行NeedForSynchronizationDemo类的main方法,结果如下所示:
Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 Deposit 2000.0 Withdrawal 250.0 Deposit 2000.0 …
相关推荐
本实例大全将全面解析`synchronized`的使用方式,包括同步方法、同步语句块、类锁和对象锁。 ### 1. 同步方法 同步方法是通过在方法声明前加上`synchronized`关键字实现的。这样,同一时间只有一个线程可以执行该...
Java中的同步锁,即`synchronized`关键字,是Java多线程编程中用于解决并发问题的重要机制。它确保了对共享资源的互斥访问,防止数据的不一致性。当我们有多线程环境并涉及到共享数据时,可能会出现竞态条件,就像...
在Java中,`synchronized`有两种使用方式:同步方法和同步代码块。 1. 同步方法: 同步方法是指在方法声明前加上`synchronized`关键字,它会锁定该方法所在的对象。对于非静态方法,锁的是当前对象实例;对于静态...
当一个方法或者代码块被synchronized修饰时,同一时刻只有一个线程可以执行该代码。在售票实例中,可能会有一个`sellTicket()`方法,用synchronized修饰,确保同一时间只有一个线程可以卖出票。 ```java public ...
2. 同步代码块:锁定对象实例,只允许一个线程访问指定的代码块。 ```java public void method() { synchronized (this) { // 代码块 } } ``` 在上述案例中,`this`表示当前对象实例,也可以替换为其他对象实例,...
在Java编程语言中,同步代码块(synchronized blocks)是一种重要的多线程控制机制,用于保证线程安全,防止数据的不一致性。本压缩包包含了两个示例代码——Example12.java和Example13.java,它们是针对同步代码块...
线程同步主要通过两种方式实现:同步块(synchronized block)和同步方法(synchronized method)。在这个实例中,我们看到了这两种方式的使用。 首先,我们看到一个未同步的`run()`方法,当`b`为`false`时,这个...
"基于Java synchronized同步锁实现线程交互" Java多线程能够提高CPU利用效率,但也容易造成线程不安全、线程死锁等问题。Java synchronized同步锁可以保证同一时刻只有一个线程操作同一资源,使用wait()、notify()...
本篇文章将详细介绍`synchronized`的两种形式:同步代码块和同步方法,并分析它们的区别。 1. **同步代码块 (Synchronized Block)** 同步代码块的语法结构如下: ```java synchronized (object) { // 需要同步...
* 若此对象对应的类中包含了多个 synchronized 修饰的方法或代码块,多个线程访问同一个对象的任意 synchronized 修饰的方法或代码块,只要有一个线程拥有了 synchronized 同步锁,其他线程不管想访问 synchronized ...
对象锁是针对类的实例对象而言的,当一个线程访问某个对象的非静态 synchronized 方法或同步代码块时,会获取到该对象的锁。这种锁确保了同一时间只有一个线程能访问该对象的成员变量。例如: ```java public class...
总结起来,Java多线程同步是通过`synchronized`关键字实现的,它可以应用于方法或代码块,保证同一时刻只有一个线程能够执行特定的代码。通过合理使用同步机制,开发者可以有效地管理并发程序中的资源访问,避免数据...
因此,确保对象的生命周期管理正确至关重要,避免在多线程环境下过早地释放可能被同步的实例。 与其他同步机制相比,`@synchronized`提供了简洁的语法,但同时也牺牲了一定的性能。例如,相比NSLock、...
如上所述,`synchronized`是可重入的,这意味着一个线程可以多次进入持有锁的同步代码块,只要每次的进入都是对同一个对象进行同步。 ### 4. 是否是公平锁? `synchronized`默认是非公平锁,不保证线程获取锁的...
1. 实例方法同步:当在实例方法前加上`synchronized`关键字时,整个方法会被视为同步块。这意味着任何时刻只有一个线程能访问该方法。例如: ```java public synchronized void add(int value) { this.count += ...
同步代码块则是通过`synchronized`关键字包裹一段代码,如`synchronized (object) { ... }`,这里的`object`是同步锁对象。 当`synchronized`作用于实例方法时,它锁定的是调用该方法的对象实例,这意味着在同一...
`synchronized`关键字在Java编程语言中扮演着至关重要的角色,它是Java实现多线程同步的主要机制。通过使用`synchronized`,可以确保同一时间只有一个线程能够执行特定代码块,从而防止数据的不一致性和线程安全问题...
- **同步块 (Synchronized Block)**:用 `synchronized` 修饰的代码块,如 `synchronized(obj) {...}`,它指定了一把锁,即 `obj` 对象。所有线程在进入此代码块前都需要获取 `obj` 的锁。 3. **示例分析**: - ...
首先,`synchronized`关键字有两种主要的用法:修饰实例方法和修饰代码块。当`synchronized`用于修饰实例方法时,它会锁定当前对象,即调用该方法的对象,使得同一时刻只有一个线程能够执行该方法。如果两个线程分别...