Java 多线程同步与锁

线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。例如一个银行账户同时被两个线程操作,一个取100块,一个存钱100块。如果取钱线程和存钱线程同时发生,就会出现异常。因此多线程同步就是要解决这个问题,如下面的代码

package com.example;
/**
 * Created by Owen Chan on 16/3/14.
 * Copyright © 2016 Owen Chan. All rights reserved.
 */
public class BankAccount {
    private int amount = 0; 
    //deposit money
    public void  depositMoney(int money){
        amount += money;
        System.out.println(System.currentTimeMillis() + "deposit money : " + money);
    }
    //withdraw money
    public void withdrawMoney(int money){
        if(amount - money < 0){
            System.out.println("account has no enough money");
            return;
        }
        amount -= money;
        System.out.println(System.currentTimeMillis() +"withdraw money : " + money);
    }
    //enquiries
    public void  enquiriesAccount(){
        System.out.println("account last: "+amount);
    }
}
package com.example;

public class MyClass {
    public static void main(String args[]) {
        final BankAccount bank = new BankAccount();
        Thread tadd = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    bank.depositMoney(10);
                    bank.enquiriesAccount();
                    System.out.println("\n");
                }
            }
        });

        Thread tsub = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    bank.withdrawMoney(10);
                    bank.enquiriesAccount();
                    System.out.println("\n");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });
        tsub.start();
        tadd.start();
    }
}

输出结果:

account has no enough money

account last: 0

1457947900621deposit money : 10

1457947900621withdraw money : 10

account last: 0

account last: 0

从结果发现,这样的输出值明显是不合理的。原因是两个线程不加控制的访问BankAccount对象并修改其数据所致。

同步和锁定

Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例有关的锁。如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放锁。

同步后的代码
package com.example;

/**
 * Created by Owen Chan on 16/3/14.
 * Copyright © 2016 Owen Chan. All rights reserved.
 */
public class BankAccount {

    private int amount = 0; //账户余额

    //deposit money
    public synchronized void  depositMoney(int money){
        amount += money;
        System.out.println(System.currentTimeMillis() + "deposit money : " + money);
    }

    //withdraw money
    public synchronized void withdrawMoney(int money){
        if(amount - money < 0){
            System.out.println("account has no enough money");
            return;
        }
        amount -= money;
        System.out.println(System.currentTimeMillis() +"withdraw money : " + money);
    }

    //enquiries
    public void  enquiriesAccount(){
        System.out.println("account last: "+amount);
    }

}

输出结果如下:

account has no enough money
account last: 0
1457949577270deposit money : 10
account last: 10
1457949577270withdraw money : 10
account last: 0

静态方法同步

要同步静态方法,需要一个用于整个类对象的锁,这个对象是就是这个类(XXX.class)。
例如:

public static synchronized int setAccount(String name){
      Xxx.name = name;
}
等价于
public static int setAccount(String name){
      synchronized(Xxx.class){
            Xxx.name = name;
      }
}

线程死锁

当两个线程被阻塞,每个线程在等待另一个线程时就发生死锁。

public class DeadlockRisk { 
    private static class Resource { 
        public int value; 
    } 
    private Resource resourceA = new Resource(); 
    private Resource resourceB = new Resource(); 

    public int read() { 
        synchronized (resourceA) { 
            synchronized (resourceB) { 
                return resourceB.value + resourceA.value; 
            } 
        } 
    } 

    public void write(int a, int b) { 
        synchronized (resourceB) { 
            synchronized (resourceA) { 
                resourceA.value = a; 
                resourceB.value = b; 
            } 
        } 
    } 
}

假设read()方法由一个线程启动,write()方法由另外一个线程启动。读线程将拥有resourceA锁,写线程将拥有resourceB锁,两者都坚持等待的话就出现死锁。

线程同步总结

1、线程同步的目的是防止多个线程访问一个数据对象时,对数据的破坏
2、线程同步方法是可以通过锁来实现,每个对象都有切仅有一个锁,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。
3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。
4、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。
5、死锁是线程间相互等待锁锁造成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值