Java线程同步
遇安.112 人气:0第一种方法:同步代码块:
作用:把出现线程安全的核心代码上锁
原理:每次只能一个线程进入,执行完毕后自行解锁,其他线程才能进来执行
锁对象要求:理论上,锁对象只要对于当前同时执行的线程是同一个对象即可
缺点:会干扰其他无关线程的执行
所以,这种只是理论上的,了解即可,现实中并不会这样用
public class 多线程_4线程同步 { public static void main(String[] args) { //定义线程类,创建一个共享的账户对象 account a=new account("abc",10000); //创建两个取钱的线程对象 new drawthread(a,"小明").start(); new drawthread(a,"小红").start(); } } //取钱的线程类 class drawthread extends Thread{ //接收处理的账户对象 private account acc; public drawthread(account acc,String name){ super(name); this.acc=acc; } public void run(){ //取钱 acc.drawmoney(10000); } } class account{ private String cartId; private double money;//账户余额 public account() { } public account(String cartId, double money) { this.cartId = cartId; this.money = money; } public String getCartId() { return cartId; } public void setCartId(String cartId) { this.cartId = cartId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public void drawmoney(double money) { //先获取是谁来取钱,线程名即是人名 String name=Thread.currentThread().getName(); //同步代码块 //作用:把出现线程安全的核心代码上锁 //原理:每次只能一个线程进入,执行完毕后自行解锁,其他线程才能进来执行 //锁对象要求:理论上,锁对象只要对于当前同时执行的线程是同一个对象即可 //缺点:会干扰其他无关线程的执行 synchronized ("遇安") {//"锁名自取,无意义" //判断账户是否够钱 if(this.money>=money){ //取钱 System.out.println(name+"来取钱成功,取了:"+money); //更新金额 this.money-=money; System.out.println(name+"取钱后剩余:"+this.money); }else{ //余额不足 System.out.println(name+"来取钱,但余额不足!"); } } } }
规范上:建议使用共享资源作为锁对象
对于实例化方法建议使用this作为锁对象
对于静态方法,建议使用字节码(类名.class)对象作为锁对象
//接上文代码 //实例化方法建议使用this作为锁对象 synchronized (this) { //判断账户是否够钱 if(this.money>=money){ //取钱 System.out.println(name+"来取钱成功,取了:"+money); //更新金额 this.money-=money; System.out.println(name+"取钱后剩余:"+this.money); }else{ //余额不足 System.out.println(name+"来取钱,但余额不足!"); } }
//静态方法建议使用类名.class作为锁对象 //每次只有一个线程能锁这个类,而类也是唯一的 public static void run(){ synchronized(account.class){ } }
第二种方法:同步方法
//同步方法 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(name+"取钱后剩余:"+this.money); }else{ //余额不足 System.out.println(name+"来取钱,但余额不足!"); } }
那么同步代码块和同步方法哪个好一点呢?
答案是:同步代码块
因为同步代码块锁的范围更小一点,同步方法锁的范围更大一点
但其实在现实中同步方法用的更多一点,因为代码简洁好写一点,更方便
第三种方法:Lock锁
JDK5后出现,更加灵活方便
Lock是接口不能直接实例化,我们需要采用它的实现类ReentrantLock来构建Lock锁对象
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class 多线程_4线程同步Lock锁 { public static void main(String[] args) { //定义线程类,创建一个共享的账户对象 account a=new account("abc",10000); //创建两个取钱的线程对象 new drawthread(a,"小明").start(); new drawthread(a,"小红").start(); } } //取钱的线程类 class drawthread2 extends Thread{ //接收处理的账户对象 private account acc; public drawthread2(account acc,String name){ super(name); this.acc=acc; } public void run(){ //取钱 acc.drawmoney(10000); } } class account2{ private String cartId; private double money;//账户余额 //final修饰后:锁对象是唯一的和不可替换的 //Lock是接口不能直接实例化,我们需要采用它的实现类ReentrantLock来构建Lock锁对象 private final Lock lock=new ReentrantLock(); public account2() { } public account2(String cartId, double money) { this.cartId = cartId; this.money = money; } public String getCartId() { return cartId; } public void setCartId(String cartId) { this.cartId = cartId; } public double getMoney() { return money; } public void setMoney(double money) { 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(name+"取钱后剩余:"+this.money); }else{ //余额不足 System.out.println(name+"来取钱,但余额不足!"); } //防止代码出现bug而不能解锁 } finally { lock.unlock();//解锁 } } }
加载全部内容