笔记
线程安全问题:多个线程同时 *** 作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题
例如下面这段代码
public class Account { private String id; private double money; public Account() { } public Account(String id, double money) { this.id = id; this.money = money; } public void DrawMoney(double money) { String name= Thread.currentThread().getName(); if (this.money>=money){ System.out.println(name+"取钱成功,吐出"+money); this.money-=money; System.out.println("余额"+this.money); }else { System.out.println(name+"来取钱,余额不足"); } } public void setId(String id) { this.id = id; } public void setMoney(double money) { this.money = money; } public String getId() { return id; } public double getMoney() { return money; } } public class MyThread extends Thread{ private Account acc; public MyThread(String name,Account acc){ super(name); this.acc=acc; } @Override public void run() { acc.DrawMoney(100000); } } public class Test { public static void main(String[] args) { Account account=new Account("1314",100000); new MyThread("小明",account).start(); new MyThread("小红",account).start(); } }
账户内只有100000元,当两个人同时取钱时,若小明取完钱,账户内的余额还未更新,小红又取了钱,那么此时两人都取了100000元(血赚),为了防止这种问题出现,就有了线程安全。那么如何实现线程安全呢。
1、synchronized同步代码块
public void DrawMoney(double money) { String name=Thread.currentThread().getName(); //同步代码块 synchronized (this){ if (this.money>=money){ System.out.println(name+"取钱成功,吐出"+money); this.money-=money; System.out.println("余额"+this.money); }else { System.out.println(name+"来取钱,余额不足"); } }}
这里对出现的问题核心代码使用synchronized进行加锁 ,每次只能有一个线程占锁进行访问,此时就实现了线程安全。
锁对象的要求:1、对于实例方法建议使用this做为锁对象
2、对于静态方法建议使用字节码(类名.class)对象做为锁对象
2、使用synchronized修饰方法
public synchronized void DrawMoney(double money) { String name= Thread.currentThread().getName(); if (this.money>=money){ System.out.println(name+"取钱成功,吐出"+money); this.money-=money; System.out.println("余额"+this.money); }else { System.out.println(name+"来取钱,余额不足"); } }
这种方法比同步代码快简约,但性能比同步代码块差一点,程序员可根据不同的使用场景进行选择运用。
3、创建锁对象的方法(这种方法很专业)
这里只展示账户类的代码,测试类和线程类和第一个代码段一样
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Account { private String id; private double money; private final Lock lock=new ReentrantLock(); //锁对象用final修饰,唯一且不可替换,非常专业 public Account() { } public Account(String id, double money) { this.id = id; this.money = money; } public void DrawMoney(double money) { String name=Thread.currentThread().getName(); lock.lock();//上锁 try{ if (this.money>=money){ System.out.println(name+"取钱成功,吐出"+money); this.money-=money; System.out.println("余额"+this.money); }else { System.out.println(name+"来取钱,余额不足"); }}finally { lock.unlock();//解锁 } } public void setId(String id) { this.id = id; } public void setMoney(double money) { this.money = money; } public String getId() { return id; } public double getMoney() { return money; } }
总结:以上就是线程安全的三种实现方法
线程安全问题出现的原因:存在多线程并发;同时访问共享资源;同时修改共享资源。
笔记结束
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)