Java基础教程——线程同步
线程同步
synchronized:同步的
例:取钱
不做线程同步的场合,假设骗子和户主同时取钱,可能出现这种情况:
- 【骗子】取款2000:账户余额1000
- 【户主】取款2000:账户余额1000
- 结果是社会财富增加1000,银行不开心。
代码如下所示:
// 账户类
class Account {
private int accountBalance = 2000;
public void withdraw(String userName, int amount) {
System.out.println(userName + "===in===");
if (accountBalance >= amount) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
accountBalance -= amount;// 取钱
System.out.println(userName + "取款" + amount + ",余额:" + accountBalance);
} else {
System.out.println(userName + "企图取款" + amount + ",但余额只有:" + accountBalance);
}
System.out.println(userName + "===out===");
}
}
class MyThread extends Thread {
@Override
public void run() {
取钱Demo.act.withdraw(getName(), 1000);
}
}
public class 取钱Demo {
static Account act = new Account();// 账户就一份
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("户主");
t2.setName("骗子");
t2.start();
t1.start();
}
}
想要银行开心,就需要对线程进行同步处理,避免出现重复取款的情况。
线程同步
方法一:锁对象
public void withdraw(String userName, int amount) {
synchronized (this) {
……
}
}
如果是静态方法,没有this,则是锁住【类名.class】
public static void withdraw(String userName, int amount) {
synchronized (Account.class) {
……
}
}
方法二:锁方法
当方法被调用时,调用线程必须获得当前对象的锁,否则将等待下去。
方法结束后,锁会被释放。
public synchronized void withdraw(String userName, int amount) {...}
方法三:ReentrantLock重入锁
ReentrantLock是java.util.concurrent.locks.Lock接口的一个实现类。(reentrant:[rɪ'entrənt]再进去)
一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大(可以中断、定时)。
API文档上建议的用法:
建议总是 立即实践,使用 lock 块来调用 try,在之前/之后的构造中,最典型的代码如下:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
应用示例:
import java.util.concurrent.locks.ReentrantLock;
// 账户类
class Account {
private int accountBalance = 2000;
private ReentrantLock lock = new ReentrantLock();
public void withdraw(String userName, int amount) {
synchronized (Account.class) {
lock.lock();
try {
System.out.println(userName + "===in===");
if (accountBalance >= amount) {
Thread.sleep(500);
accountBalance -= amount;// 取钱
System.out.println(userName + "取款" + amount + ",余额:" + accountBalance);
} else {
System.out.println(userName + "企图取款" + amount + ",但余额只有:" + accountBalance);
}
System.out.println(userName + "===out===");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
练习:买票
(未做线程同步,请实现线程同步)
import java.util.Random;
public class 卖票 {
public static void main(String[] args) {
// 一个Runnable实例对象
SellTicket st = new SellTicket();
// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
class SellTicket implements Runnable {
// 定义票数
private int tickets = 100;
private void sell() {
if (tickets > 0) {
// 模拟售票过程
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在出售第" + (tickets--) + "张票");
}
}
@Override
public void run() {
while (tickets > 0) {
sell();
// 模拟空闲过程
try {
Thread.sleep(new Random().nextInt(11) * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Java基础教程——线程同步的更多相关文章
- Java基础-多线程-③线程同步之synchronized
使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...
- Java基础8-多线程;同步代码块
作业解析 利用白富美接口案例,土豪征婚使用匿名内部类对象实现. interface White{ public void white(); } interface Rich{ public void ...
- Java基础教程——线程局部变量
线程局部变量 ThreadLocal,线程局部变量,不提供锁,不做线程共享,而是为每个线程提供变量的独立副本. import java.util.concurrent.*; public class ...
- Java基础教程——线程池
启动新线程,需要和操作系统进行交互,成本比较高. 使用线程池可以提高性能-- 线程池会提前创建大量的空闲线程,随时待命执行线程任务.在执行完了一个任务之后,线程会回到空闲状态,等待执行下一个任务.(这 ...
- Java基础教程——线程状态
线程状态 JAVA定义了6种线程状态: Thread.State public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, ...
- Java基础教程——线程通信
线程通信:等待.唤醒 Object方法 这些方法在拥有资源时才能调用 notify 唤醒某个线程.唤醒后不是立马执行,而是等CPU分配 wait 等待,释放锁,不占用CPU资源 notifyAll 唤 ...
- Java基础教程:多线程基础(2)——线程间的通信
Java基础教程:多线程基础(2)——线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 ...
- Java基础教程:多线程基础——线程池
Java基础教程:多线程基础——线程池 线程池 在正常负载的情况瞎,通过为每一个请求创建一个新的线程来提供服务,从而实现更高的响应性. new Thread(runnable).start() 在生产 ...
- Java基础教程:多线程基础(1)——基础操作
Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...
随机推荐
- 多快好省地使用pandas分析大型数据集
1 简介 pandas虽然是个非常流行的数据分析利器,但很多朋友在使用pandas处理较大规模的数据集的时候经常会反映pandas运算"慢",且内存开销"大". ...
- STM32入门系列-STM32时钟系统,时钟初始化配置函数
在前面推文的介绍中,我们知道STM32系统复位后首先进入SystemInit函数进行时钟的设置,然后进入主函数main.那么我们就来看下SystemInit()函数到底做了哪些操作,首先打开我们前面使 ...
- pandas对列求和
了解更多,请关注公众号"轻松学编程" 一行代码实现对列求和 使用pandas把列表中的字典元素转成二维数组,然后使用pandas函数实现对每一列求和. 代码: import pan ...
- 基于Django的图书推荐系统和论坛
基于Django的图书推荐系统和论坛 关注公众号"轻松学编程"回复"图书系统"获取源码 一.基本功能 登录注册页面 基于协同过滤的图书的分类,排序,搜索,打分功 ...
- python实现有趣的数学逻辑程序
1.无重复数字的三位数 题目:有1.2.3.4个数字, 能组成多少个互不相同且无重复数字的三位数? 都是多少? for i in range(1,5): for j in range(1,5): fo ...
- 【漏洞复现】Shiro<=1.2.4反序列化漏洞
0x01 概述 Shiro简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从 ...
- 美团笔试题_ACM最多队伍
题目: 选择队伍参加ACM比赛,可以选择的人由N+M组成,N代表N个擅长算法的人,M代表M个擅长编程的人,选择要求:每个队伍三个人,每个队伍中至少有一个擅长算法的人,至少有一个擅长编程的人.求可以组成 ...
- 【SpringCloud】07.应用间的通信
应用间通信 HTTP vs RPC Spring Cloud (HTTP) Dubbo (RPC) 1.SpringCloud中服务间两种restful调用方式 RestTemplate Feign ...
- php执行exec、xsell_exec命令失败
在php.ini下进行更改 查找disable_function 去掉exec xsell_exec 重启php
- [MIT6.006] 23. Computational Complexity 计算复杂度
这节课主要讲的计算复杂度,一般有三种表达不同程度的计算复杂度,如下图所示: P:多项式时间: EXP:指数时间: R:有限时间内. 上图还给了一些问题的计算复杂度的对应结果,关于一些细节例如NP, N ...