Java基础教程——线程同步
Posted tigerlion
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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基础教程——线程同步的主要内容,如果未能解决你的问题,请参考以下文章
阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_4_解决线程安全问题_同步代码块