线程同步机制
Posted 技术很low的瓜贼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程同步机制相关的知识,希望对你有一定的参考价值。
文章目录
线程同步机制
概念:
- 当多个线程同时访问一种共享资源时,可能会造成数据的覆盖等不一致问题,此时需要对线程之间进行通信和协调,该机制叫做线程同步机制
- 多个线程并发读写同一个临界资源时会发生线程并发安全问题
异步操作:多线程并发的操作,各自独立运行
同步操作:多线程串行的操作,先后执行的顺序
实现方式:
- 在Java语言中使用synchronized关键字来实现同步/对象锁机制从而保证线程执行的原子性
使用同步代码块方式:
使用同步代码块的方式实现部分代码的锁定,格式如下:
synchronized(类类型的引用)
编写所有需要锁定的代码;
案例代码:
package 线程;
/**
* 线程的同步机制
* 同步代码块的方式一
*/
public class AccountTest implements Runnable
private int balance; // 用于描述账户余额
public AccountTest()
public AccountTest(int balance)
this.balance = balance;
@Override
public String toString()
return "AccountTest" +
"balance=" + balance +
'';
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public void run()
synchronized (this)
System.out.println(Thread.currentThread().getName() + "正在操作");
int temp = getBalance();
// 模拟取款
System.out.println("正在取款请稍后");
if (temp > 200)
System.out.println("正在出钞,请稍后");
temp -= 200;
try
Thread.sleep(5000);
System.out.println("取钞完成");
catch (InterruptedException e)
e.printStackTrace();
else
System.out.println("余额不足");
// 模拟将最新的账户余额写入后台
setBalance(temp);
System.out.println(getBalance());
public static void main(String[] args)
AccountTest at = new AccountTest(1000);
Thread t1 = new Thread(at);
Thread t2 = new Thread(at);
t1.start();
t2.start();
try
t1.join();
t2.join();
catch (InterruptedException e)
e.printStackTrace();
使用同步方法的方式
直接使用synchronized关键字来修饰整个方法即可
该方式等价于:
synchronized(this) 整个方法体的代码
案例代码:
- Runnable代码:
/**
* 线程的同步机制
* 直接使用synchronized来修饰整个方法
*/
public class AccountTest3 implements Runnable
private int balance; // 用于描述账户余额
public AccountTest3()
public AccountTest3(int balance)
this.balance = balance;
@Override
public String toString()
return "AccountTest" +
"balance=" + balance +
'';
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public synchronized void run()
System.out.println(Thread.currentThread().getName() + "正在操作");
int temp = getBalance();
// 模拟取款
System.out.println("正在取款请稍后");
if (temp > 200)
System.out.println("正在出钞,请稍后");
temp -= 200;
try
Thread.sleep(5000);
System.out.println("取钞完成");
catch (InterruptedException e)
e.printStackTrace();
else
System.out.println("余额不足");
// 模拟将最新的账户余额写入后台
setBalance(temp);
System.out.println(getBalance());
public static void main(String[] args)
AccountTest at = new AccountTest(1000);
Thread t1 = new Thread(at);
Thread t2 = new Thread(at);
t1.start();
t2.start();
try
t1.join();
t2.join();
catch (InterruptedException e)
e.printStackTrace();
- Thread代码:
/**
* 线程的同步机制
* synchronized直接修饰
*/
public class AccountTest4 extends Thread
private int balance; // 用于描述账户余额
public AccountTest4()
public AccountTest4(int balance)
this.balance = balance;
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public synchronized void run()
int temp = getBalance();
System.out.println("正在取款,请稍后");
if (temp >= 200)
System.out.println("正在出钞");
temp -= 200;
try
Thread.sleep(5000);
catch (InterruptedException e)
e.printStackTrace();
setBalance(temp);
System.out.println("余额" + getBalance());
public static void main(String[] args)
AccountTest2 at2 = new AccountTest2(1000);
at2.start();
AccountTest2 at22 = new AccountTest2(1000);
at22.start();
try
at2.join();
at22.join();
catch (InterruptedException e)
e.printStackTrace();
静态方法锁定的方式
- 当我们对一个静态方法加锁,如:
public synchronized static void xxx()….
- 那么该方法锁的对象是类对象。每个类都有唯一的一个类对象。获取类对象的方式:类名.class
- 静态方法与非静态方法同时使用了synchronized后它们之间是非互斥关系的
- 原因在于:静态方法锁的是类对象而非静态方法锁的是当前方法所属对象
- 使用synchronized保证线程同步应当注意
- 多个需要同步的线程在访问同步块时,看到的应该是同一个锁对象引用。
- 在使用同步块时应当尽量减少同步范围以提高并发的执行效率
案例代码:
/**
* 线程的同步机制
* 同步代码块方式二
*/
public class AccountTest2 extends Thread
private int balance; // 用于描述账户余额
private static Demo dm = new Demo();
public AccountTest2()
public AccountTest2(int balance)
this.balance = balance;
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public void run()
synchronized (dm)
int temp = getBalance();
System.out.println("正在取款,请稍后");
if (temp >= 200)
System.out.println("正在出钞");
temp -= 200;
try
Thread.sleep(5000);
catch (InterruptedException e)
e.printStackTrace();
setBalance(temp);
System.out.println("余额" + getBalance());
public static void main(String[] args)
AccountTest2 at2 = new AccountTest2(1000);
at2.start();
AccountTest2 at22 = new AccountTest2(1000);
at22.start();
try
at2.join();
at22.join();
catch (InterruptedException e)
e.printStackTrace();
class Demo
使用Lock(锁)实现线程同步
- 从Java5开始提供了更强大的线程同步机制—使用显式定义的同步锁对象来实现
- java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具
- 该接口的主要实现类是ReentrantLock类,该类拥有与synchronized相同的并发性,在以后的线程安全控制中,经常使用ReentrantLock类显式加锁和释放锁
- 常用方法:
方法 | 功能 |
---|---|
ReentrantLock() | 使用无参方式构造对象 |
void lock() | 获取锁 |
void unlock() | 释放锁 |
案例代码:
- Runnable代码:
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程的同步机制
* 使用Lock实现线程的同步
*/
public class AccountTest5 implements Runnable
private int balance; // 用于描述账户余额
private ReentrantLock lock = new ReentrantLock(); // 准备了一把锁
public AccountTest5()
public AccountTest5(int balance)
this.balance = balance;
@Override
public String toString()
return "AccountTest" +
"balance=" + balance +
'';
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public void run()
lock.lock(); // 关锁
System.out.println(Thread.currentThread().getName() + "正在操作");
int temp = getBalance();
// 模拟取款
System.out.println("正在取款请稍后");
if (temp > 200)
System.out.println("正在出钞,请稍后");
temp -= 200;
try
Thread.sleep(5000);
System.out.println("取钞完成");
catch (InterruptedException e)
e.printStackTrace();
else
System.out.println("余额不足");
// 模拟将最新的账户余额写入后台
setBalance(temp);
System.out.println(getBalance());
lock.unlock(); // 开锁
public static void main(String[] args)
AccountTest at = new AccountTest(1000);
Thread t1 = new Thread(at);
Thread t2 = new Thread(at);
t1.start();
t2.start();
try
t1.join();
t2.join();
catch (InterruptedException e)
e.printStackTrace();
- Thread代码:
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程的同步机制
* 使用Lock锁实现同步机制
*/
public class AccountTest6 extends Thread
private int balance; // 用于描述账户余额
private ReentrantLock lock = new ReentrantLock(); // 准备一把锁
public AccountTest6()
public AccountTest6(int balance)
this.balance = balance;
public int getBalance()
return balance;
public void setBalance(int balance)
this.balance = balance;
@Override
public void run()
lock.lock();
int temp = getBalance();
System.out.println("正在取款,请稍后");
if (temp >= 200)
System.out.println("正在出钞");
temp -= 200;
try
Thread.sleep(5000);
catch (InterruptedException e)
e.printStackTrace();
setBalance(temp);
System.out.println("余额" + getBalance());
lock.unlock();
public static void main(String[] args)
AccountTest2 at2 = new AccountTest2(1000JavaSE:线程同步机制