`

Java 同步的一个例子

阅读更多
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?

在本文之前,请参阅《Java线程:线程的同步与锁》,本文是在此基础上所写的。

对于同步,在具体的Java代码中需要完成一下两个操作:

把竞争访问的资源标识为private;

同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。

当然这不是唯一控制并发安全的途径。

synchronized关键字使用说明

synchronized只能标记非抽象的方法,不能标识成员变量。

为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。


/**
* Java线程:线程的同步
*
* @author leizhimin 2009-11-4 11:23:32
*/
public class Test {
public static void main(String[] args) {
User u = new User("张三", 100);
MyThread t1 = new MyThread("线程A", u, 20);
MyThread t2 = new MyThread("线程B", u, -60);
MyThread t3 = new MyThread("线程C", u, -80);
MyThread t4 = new MyThread("线程D", u, -30);
MyThread t5 = new MyThread("线程E", u, 32);
MyThread t6 = new MyThread("线程F", u, 21);

t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}

class MyThread extends Thread {
private User u;
private int y = 0;

MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}

public void run() {
u.oper(y);
}
}

class User {
private String code;
private int cash;

User(String code, int cash) {
this.code = code;
this.cash = cash;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

/**
* 业务方法
* @param x 添加x万元
*/
public synchronized void oper(int x) {
try {

this.cash += x;
Thread.sleep(10L);
System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public String toString() {
return "User{" +
"code='" + code + '\'' +
", cash=" + cash +
'}';
}
}

输出结果:

线程A运行结束,增加“20”,当前用户账户余额为:120
线程F运行结束,增加“21”,当前用户账户余额为:141
线程E运行结束,增加“32”,当前用户账户余额为:173
线程C运行结束,增加“-80”,当前用户账户余额为:93
线程B运行结束,增加“-60”,当前用户账户余额为:33
线程D运行结束,增加“-30”,当前用户账户余额为:3

Process finished with exit code 0


反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:

线程A运行结束,增加“20”,当前用户账户余额为:61
线程D运行结束,增加“-30”,当前用户账户余额为:63
线程B运行结束,增加“-60”,当前用户账户余额为:3
线程F运行结束,增加“21”,当前用户账户余额为:61
线程E运行结束,增加“32”,当前用户账户余额为:93
线程C运行结束,增加“-80”,当前用户账户余额为:61

Process finished with exit code 0

很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。

可见同步的重要性。


注意:

通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于 java.lang.Object类。

void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

结合以上方法,处理多线程同步与互斥问题非常重要,著名的生产者-消费者例子就是一个经典的例子,任何语言多线程必学的例子。
分享到:
评论

相关推荐

    关于CoreJava同步的疑惑例子

    在这个“关于CoreJava同步的疑惑例子”中,我们将探讨Java中的同步机制,以及如何通过示例代码`Bank.java`, `TransferRunnable.java`, 和 `SynchBankTest.java`来理解这个概念。 1. **同步的必要性** 当多个线程...

    java实现windows机器系统时间同步网络时间例子

    java类获取网络时间操作cmd命令(打成jar包了,就一个sysTimeTest类,30行代码用反编译工具一看就懂,网上也有很多例子)。然后打成jar包,windows批处理操作,单次同步更新windows系统时间,每天定时同步更新windows...

    java多线程同步例子

    java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料

    java简单程序小例子

    另外,集合框架是Java库的一个重要组成部分,包括List、Set和Map接口,以及它们的实现类,如ArrayList、LinkedList、HashSet、HashMap等,这些数据结构提供了存储和操作对象的多种方式。 线程是Java的另一大特色,...

    java线程同步的例子.doc

    `ThreadDemo`实现了`Runnable`接口,其中包含两个版本的线程同步:一个是通过`synchronized`方法,另一个是通过`synchronized`代码块。 1. **synchronized代码块**: 在`ThreadDemo`的第一个实现中,`sale()`方法...

    java线程同步的例子.pdf

    `synchronized`关键字作用于一个对象(在这个例子中是字符串`str`),它创建了一个监视器或者称为锁。当一个线程进入同步代码块并执行其中的语句时,该线程会获取到`str`对象的锁,其他尝试进入同步代码块的线程会被...

    JAVA代码大全的例子

    总的来说,"JAVA代码大全的例子"是一个宝贵的教育资源,它涵盖了Java编程的各个方面,无论你是初学者还是经验丰富的开发者,都能从中受益。通过逐个研究这些例子,你将能够逐步提高你的编程技能,更好地理解和运用...

    一个java Quartz的小例子

    Java Quartz 是一个强大的开源作业调度框架,用于在Java应用程序中创建和管理计划任务。它允许开发者精确地安排任务执行,可以按需重复、延迟或在特定时间触发。在这个小例子中,我们将深入理解如何使用Java Quartz...

    100个Java经典例子后端- Java

    Java是一种广泛使用的面向对象的编程语言,以其跨平台...每个例子都可能是一个独立的功能模块,通过组合这些模块,开发者可以构建出复杂的应用系统。不断实践和理解这些例子,将有助于提升你的编程技能和问题解决能力。

    Java线程同步例子.pdf

    在Java中,线程同步是保证多线程安全...上述Java线程同步例子中涉及到的代码虽然是片段,但涵盖了线程同步处理的多个重要方面,帮助我们理解和使用Java线程同步机制,以及在设计和实现多线程应用程序时的实践和技巧。

    java synchronize 线程同步

    在引申的例子中,通过定义一个静态的`lock`对象,然后在同步代码块中使用它,确保了所有线程在执行`execute()`方法时都会获取这把全局锁,从而实现了同步。 ```java public class TestThread { private static ...

    java同步synchronized关键字用法示例

    在这个例子中,`increment()`、`decrement()`和`value()`方法都是同步的,这意味着任何时候只有一个线程可以调用它们。 总之,`synchronized`关键字在Java多线程编程中扮演着关键角色,确保了共享资源的安全访问,...

    java线程同步实例

    哲学家就餐问题是多线程编程中一个经典的同步问题。该问题描述为五位哲学家围坐在一张圆桌旁,桌上放着五个筷子(或者说是餐叉),每个哲学家在思考的时候不使用筷子,而当他们想吃饭时,则需要同时拿到左右两边的...

    同步两个数据库的数据

    在这个rar包中的“SynOTEXAM”可能是代码文件名,它可能包含一个Python、Java、SQL或其他语言编写的脚本,用于实现上述的同步操作。通常,这样的脚本会包括以下步骤: 1. **连接数据库**:使用数据库驱动程序建立到A...

    java线程同步的例子[文].pdf

    在这个例子中,创建了4个线程,它们共享同一个`tickets`变量,`synchronized`确保每次只有一个线程能够减小`tickets`并打印售票信息。 2. **synchronized 方法**: 第二个`ThreadDemo`类中,`sale()`方法被声明为`...

    Java线程的简单例子

    当一个类实现Runnable接口时,只需要重写run()方法,然后通过Thread类的构造函数传入Runnable实例来创建线程。另一种方式是直接继承Thread类,覆盖其run()方法,然后直接调用start()启动新线程。这两种方法中,实现...

    支持10000同步锁,Spring Boot,Java

    在这个例子中,`increment()`、`decrement()`和`value()`方法都用synchronized修饰,确保了它们在同一时间只能被一个线程访问。 然而,synchronized锁有一些限制,比如它不提供公平性保证(即线程获取锁的顺序可能...

    菜鸟编写java前期的例子 java百例

    "菜鸟编写java前期的例子 java百例" 提供了一系列简单的Java代码示例,旨在帮助初学者理解和掌握Java的基础概念与语法。这些例子是学习Java编程的好起点,它们涵盖了基本的数据类型、控制结构、函数、类和对象等核心...

Global site tag (gtag.js) - Google Analytics