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方法. ...
随机推荐
- Python批量图片识别并翻译——我用python给女朋友翻译化妆品标签
Python批量图片识别并翻译--我用python给女朋友翻译化妆品标签 最近小编遇到一个生存问题,女朋友让我给她翻译英文化妆品标签.美其名曰:"程序猿每天英语开发,英文一定很好吧,来帮我翻 ...
- App测试工具大全,收藏这篇就够了
随着移动互联网的高速发展,App 应用非常火,测试工程师也会接触到各种 app 应用.除了人工测试之外,也可以通过一些测试工具来提高我们的测试效率,以下对于我用过或听过的 app 测试工具做了一个统一 ...
- shell脚本之字符串测试表达式
1.字符串测试操作符 字符串测试操作符的作用有:比较两个字符串是否相同.字符串的长度是否为零,字符串是否为NULL(注:bash区分零长度字符串和空字符串等) 下表为常用字符串操作符 也可以通过man ...
- [Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining
传送门:https://www.luogu.org/problemnew/show/P2891 题面 \ Solution 网络流 先引用一句真理:网络流最重要的就是建模 今天这道题让我深有体会 首先 ...
- ABP框架中一对多,多对多关系的处理以及功能界面的处理(1)
在我们开发业务的时候,一般数据库表都有相关的关系,除了单独表外,一般还包括一对多.多对多等常见的关系,在实际开发过程中,需要结合系统框架做对应的处理,本篇随笔介绍基于ABP框架对EF实体.DTO关系的 ...
- 《<SPRING5高级编程(第5版)>_王净译》笔记-【目录】
第一次写这玩意,不知道什么时候能写完,今天项目比较近,期望年底能看完吧. 先定个小目标 20201228 完成 第1章 Spring介绍 第2章 入门 第3章 在Spring中引入IoC和DI 第4章 ...
- 利用日志文件getshell
一.包含日志文件漏洞利用概述 当我们没有上传点,并且也没有url_allow_include功能时,我们就可以考虑包含服务器的日志文件. 利用思路也比较简单,当我们访 ...
- waf 引擎云原生调研---扫盲
概念: lstio Istio是一个用于服务治理的开放平台 Istio是一个Service Mesh形态的用于服务治理的开放平台 Istio是一个与Kubernetes紧密结合的适用于云原生场景的Se ...
- 邻居子系统1.5 neigh output
1.5.1 当邻居项不处于NUD_CONNECTD状态时,不允许快速路径发送报文,函数neigh_resolve_output 用于慢而安全的输出,通常用初始化neigh_ops结构 来实例outpu ...
- ssh2中的添,删,查,改。
1.spring封装的HibernateTemplate类的一些操作方法. 2.session提供的根据主键ID进行添.删.查.改的基本方法. 由session得到的hql语句 由session得到的 ...