多线程编程
线程同步
为什么同步
-为什么需要同步?
-防止多个线程访问一个数据对象时,对数据造成破坏
-线程的同步保证多线程安全访问竞争资源的一种手段
同步和锁定
-关键字:synchronized
-java中每个对象都有一个内置锁
-当程序运行到synchronized同步方法或代码块时,自动获得锁
-一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁。
对于同步,一般在Java中需要两步:
-将竞争访问的资源标识为peivate
-使用synchronized关键字同步方法或代码块。当synchronized方法执行完或出现异常时,会自动释放锁。
eg: 模拟某银行卡账号上有500元。一人拿着存折去取钱,同时另一人拿银行卡去ATM取钱,各取钱500元。
public class ThreadDemo3 {
public static void main(String[] args) {
Bank bank = new Bank();
BankThread b1 = new BankThread(bank);//模拟窗口取钱
BankThread b2 = new BankThread(bank);//模拟ATM取钱
b1.start();
b2.start();
}
}
class BankThread extends Thread{
private Bank bank = null;
public BankThread(Bank bank) {
this.bank = bank;
}
@Override
public void run() {
//取钱
bank.getMoney(400);
}
}
class Bank {
private double money=500;
public Bank(){}
public Bank(double money){
this.money = money;
}
//synchronized 锁 线程同步
public synchronized void getMoney(double getMoney){
if(getMoney<0){
System.out.println("取款金额不能为负!\n余额:"+money);
}else if(money-getMoney<0){
System.out.println("余额不足,取款失败!\n余额:"+money);
}else if(money<=0){
System.out.println("取款金额超额,取款失败!\n余额:"+money);
}
else{
//模拟取钱时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("取款:"+getMoney);
money-=getMoney;
System.out.println("余额:"+money);
}
}
}
同步产生死锁的原因:
-当一个线程已经锁取了对象1的锁,同时又想获取对象2的锁。而此时,另一个线程获取了对象2的锁,而又想获取对象1的锁。这种互相等待对方释放锁的过程,会导致“死锁”。
eg: 死锁举例
[为防止死锁,尽量不要在synchronized同步代码块中嵌套synchronized同步代码块]
public class DieThreadDemo {
public static void main(String[] args) {
Example example = new Example();
DieThread1 dt1 = new DieThread1(example);
dt1.start();
DieThread2 dt2 = new DieThread2(example);
dt2.start();
}
}
class DieThread1 extends Thread{
private Example example=null;
public DieThread1(Example example) {
super();
this.example = example;
}
@Override
public void run() {
example.method1();
}
}
class DieThread2 extends Thread{
private Example example=null;
public DieThread2(Example example) {
super();
this.example = example;
}
@Override
public void run() {
example.method2();
}
}
class Example{
private Object obj1 = new Object();
private Object obj2 = new Object();
public void method1(){
synchronized (obj1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("method1");
}
}
}
public void method2(){
synchronized (obj2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("method2");
}
}
}
}