线程同步学习一
线程不安全举例,存钱取钱 账户余额有时为负数。
package threadStudy; /** * 模拟线程不安全 存钱取钱 */ public class SynTest1 { public static void main(String[] args) { Account account = new Account("王五的银行卡", 1000); Withdraw withdraw1 = new Withdraw(account, 800); Withdraw withdraw2 = new Withdraw(account, 700); Thread t1 = new Thread(withdraw1, "husband"); Thread t2 = new Thread(withdraw2, "wife"); t1.start(); t2.start(); } } // 账户 class Account { private String name; private int money; public Account(String name, int money) { this.name = name; this.money = money; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } // 取钱的线程 class Withdraw implements Runnable { private Account account; private int money; private int balance; public Withdraw(Account account, int money) { super(); this.account = account; this.money = money; } @Override public void run() { if (account.getMoney() - money < 0) { return; } try { Thread.sleep(100); //模拟网络延时 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } balance = account.getMoney() - money; account.setMoney(balance); System.out.println(Thread.currentThread().getName() + "取了" + money + "---->账户余额为:" + balance); } }
会出现以上两种结果,都是错误的。
并发:指同一个对象被多个线程同时操作。
并发可能会导致数据不一致,存在线程安全等问题。
解决此问题可以使用synchronized关键字修饰方法(锁的是this对象) 或者 代码块
如下解决上面的不同步问题 采用的是synchronized代码块 指定要锁的对象是哪个
package threadStudy; /** * 模拟线程不安全 存钱取钱 */ public class SynTest1 { public static void main(String[] args) { Account account = new Account("王五的银行卡", 1200); Withdraw withdraw1 = new Withdraw(account, 800); Withdraw withdraw2 = new Withdraw(account, 700); Thread t1 = new Thread(withdraw1, "husband"); Thread t2 = new Thread(withdraw2, "wife"); t1.start(); t2.start(); } } // 账户 class Account { private String name; private int money; public Account(String name, int money) { this.name = name; this.money = money; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } // 取钱的线程 class Withdraw implements Runnable { private Account account; private int money; private int balance; public Withdraw(Account account, int money) { super(); this.account = account; this.money = money; } @Override public void run() { if (account.getMoney() <= 0) return; test(); } private void test() { // 同步关键字加在这里 锁不住 因为默认锁的是this对象 此处即Withdraw对象 应该锁accout对象 synchronized (account) { if (account.getMoney() - money < 0) { return; } try { Thread.sleep(100); // 模拟网络延时 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } balance = account.getMoney() - money; account.setMoney(balance); System.out.println(Thread.currentThread().getName() + "取了" + money + "---->账户余额为:" + balance); } } }
推荐使用synchronized代码块 能够实现更细粒度的控制。