【多线程】多线程编程:线程同步

来源:互联网 发布:淘宝会查物流重量吗 编辑:程序博客网 时间:2024/05/19 00:51

线程同步:

为什么需要同步?

  • 线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏。
  • 线程的同步是保证多线程安全访问竞争资源的一种手段

同步和锁:

  • Java中每个对象都有一个内置锁
  • 获得一个对象的锁也称为:获取锁;锁定对象;在对象上锁定;在对象上同步
  • 一个对象只有一个锁,所以如果一个线程获得该锁,该对象上的其他线程就没有可以获得的锁,直到第一个线程释放锁。也意味着任何其他线程都不能进入synchronized方法或代码块。
  • 当程序运行到synchronized同步方法或代码块时,该对象锁才起作用
  • 当线程运行到非静态的synchronied同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁,当线程运行到synchronized同步代码块时,自动获得锁定对象的锁。

如何理解:

很多人(线程)都想进入一个房间(对象),但是这个房间(对象)只有一把钥匙(锁),一次只能进一个人(线程)。要想进入房间,每次只能有一个人(线程)拿着钥匙(锁)进入房间(进入synchronized)。下一个人(线程)要等待上一个人(线程)走出房间(退出synchronized),把锁(钥匙)给自己,才能访问这个房间(对象)

对于同步,一般而言Java代码中需要完成两个操作:

  • 把竞争访问的资源标识为private私有
  • 同步哪些需要访问资源的代码,使用synchronized关键字来修饰方法或代码块,当synchronized方法执行完或发生异常时,会自动释放锁。

Code Demo:

模拟银行账户取款的资源竞争:一个银行账户支持在柜台和ATM机上取款,但是这两种取款方式不能同时进行。可以把这两种取款方式看做两个线程,他们竞争访问的资源就是银行账户中的存款。

public class BankDemo {     public static void main(String[] args) {          BankAccount bankAccount=new BankAccount();          BankThread counter=new BankThread(bankAccount);          counter.start();          BankThread ATM=new BankThread(bankAccount);          ATM.start();     }}class BankThread extends Thread{     private BankAccount bankAccount=null;     public BankThread(BankAccount bankAccount){          this.bankAccount=bankAccount;     }     @Override     public void run() {          //从银行账户上取走400块          int money=bankAccount.takeMoney(400);          System.out.println("Take Money from your account:"+money);     }}class BankAccount{     private long deposit=5000;     //当一个线程调用同步方法时,这个线程就获取了当前对象的锁     //其他线程再调用时,只能等待。     public synchronized long takeMoney(long number){          if(number<0){              return -1;          }else if(deposit<0){              return -2;          }else if(number-deposit>0){              return -3;          }else{              try {                   //模拟取钱时的等待时间                   Thread.sleep(1000);              } catch (InterruptedException e) {                   e.printStackTrace();              }              deposit-=number;              System.out.println("Deposit: "+deposit);          }          return deposit;     }}

同步产生死锁的原因:

  • 当一个线程已经获取对象1的锁,同时又想获取对象2的锁,而此时另一个线程当前已经持有的对象2的锁,而又想获取对象1的锁。这种互相等待对方释放锁的过程会导致死锁
  • 尽量避免嵌套同步块
public class DeadLockDemo {     public static void main(String[] args) {          Example example=new Example();          DeadThread1 thread1=new DeadThread1(example);          thread1.start();          DeadThread2 thread2=new DeadThread2(example);          thread2.start();     }}class DeadThread1 extends Thread{     private Example example=null;     public DeadThread1(Example example){          super();          this.example=example;     }     @Override     public void run() {          example.method1();     }}class DeadThread2 extends Thread{     private Example example=null;     public DeadThread2(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) {                   e.printStackTrace();              }              synchronized (obj2){                   System.out.println("method1");              }          }     }     public void method2(){          synchronized (obj2){              try {                   Thread.sleep(1000);              } catch (InterruptedException e) {                   e.printStackTrace();              }              synchronized (obj1){                   System.out.println("method2");              }          }     }
0 0
原创粉丝点击