线程安全问题
-
如何解决线程安全问题:
加锁:synchronized 线程同步关键字,线程同步锁。可以修饰方法,也可以使用同步代码块 -
同步代码块:可以使线程同步。
synchronized (线程共享对象){
}-
同步指的是线程与线程之间发生了等待关系
例如:有两个线程A、B,A线程执行的时候B线程必须等待 -
synchronized (线程共享对象){}
假设当前程序有t1、t2线程,this我们一般称之为对象锁,如果t1线程先来到同步代码块,发现this对象没有被占有这时t1线程会占有这把锁,然后执行代码块中的内容,在t1线程没有结束前,t2线程过来了,发现this对象已经被占有
那这时t2线程必须在锁池等待,等到t1释放this对象锁,t2才能重新持有若用synchronized直接修饰方法,那当前对象锁一定是this,缺点:会把整个方法体中的内容全部锁住,会降低程序的执行效率
-
synchronized 简单用法
- synchronized可以修饰静态方法,当前的锁就不是对象锁了,而是类锁
package com.itguo.thread;
public class ThreadTest07 {
public static void main(String[] args) {
CreateThread02 createThread01 = new CreateThread02();
CreateThread02 createThread02 = new CreateThread02();
Thread t1 = new Thread(createThread01);
Thread t2 = new Thread(createThread02);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class CreateThread02 implements Runnable{
@Override
public void run() {
CreateThread02.getMethod01();
CreateThread02.getMethod02();
}
/**
* synchronized可以修饰静态方法,当前的锁就不是对象锁了,而是类锁
*/
public static synchronized void getMethod01(){
System.out.println("begin!!!!");
}
public static synchronized void getMethod02(){
System.out.println("end!!!!!");
}
}
- 结果
begin!!!!
end!!!!!
begin!!!!
end!!!!!
线程模拟银行取钱
- Account类
package com.itguo.account;
public class Account {
private String accountName;
private double balance;
public Account() {
}
public Account(String accountName, double balance) {
this.accountName = accountName;
this.balance = balance;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
/**
* 取钱的方法
* @param money
*/
//public synchronized void getMoney(double money){ 用synchronized修饰方法体
public void getMoney(double money){
//同步代码块,this代表的就是线程t1和t2的共享对象account,这里account仅仅是t1线程和t2线程的共享对象
synchronized (this){
//先获取当前余额
double balance = this.getBalance();
try {
//模拟网络延迟
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在当前余额中扣除
setBalance(balance-money);
System.out.println(Thread.currentThread().getName()+"取走了"+money+"元,账户剩余"+this.getBalance());
}
}
}
- AccountThread类
package com.itguo.account;
public class AccountThread implements Runnable{
private Account account;
public AccountThread(Account account) {
this.account = account;
}
@Override
public void run() {
//调用取款的方法
account.getMoney(5000);
}
}
-
主函数
package com.itguo.account; public class AccountTest { public static void main(String[] args) { //创建账户对象 Account account = new Account("百事",10000); //创建线程对象 Thread t1 = new Thread(new AccountThread(account)); Thread t2 = new Thread(new AccountThread(account)); //设置线程名称 t1.setName("可口"); t2.setName("可乐"); //启动线程 t1.start(); t2.start(); } }