zoukankan      html  css  js  c++  java
  • 多线程——线程同步,死锁

    线程同步

    为什么需要同步

    ①   线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏。

    ②   线程的同步是保证多线程安全访问竞争资源的一种手段。

    同步和锁

    ①   Java中每一个对象都有一个内置锁。

    ②   当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁;当程序运行到synchronized同步代码块时,自动获得锁定对象的锁。

    ③   获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。当程序运行到synchronized同步方法或代码块时该对象锁才起作用。

    ④   一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放锁。这也意味着任何其他线程都不能进入synchronized方法或代码块,直到该锁被释放。释放锁是指持锁线程退出了synchronized同步方法或代码块。

     

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

    ①   把竞争访问的资源标识为private。

    ②   同步那些访问资源的代码,使用synchronized关键字执行完成或发生异常时,会自动释放。

     

    示例需求:

    ①   某银行卡账号上有500元现金。一个人拿着存折去取钱,同时另一个人拿着卡去ATM上取钱,各自取钱400元。

    ②   要求取钱过程中不能出现资源竞争:比如400元被取出两次,银行卡的账目不能小于0。

    银行类及线程

     1 class Bank {
     2     private int money = 500;
     3 
     4     // 取钱的方法,返回取钱的数目
     5     //当一个线程去调用同步方法的时候,这个线程就获取了当前对象的锁。
     6     //其他线程当调用同步方法的时候只能等待,因为无法获取对象的锁,
     7     //只有等第一个线程释放对象的锁方可进入
     8     public synchronized int getMoney(int number) {
     9         synchronized (this) {
    10             if (number < 0) {
    11                 return -1;
    12             } else if (money < 0) {
    13                 return -2;
    14             } else if (number - money > 0) {
    15                 return -3;
    16             } else {
    17                 try {
    18                     Thread.sleep(1000);// 模拟取钱的时间
    19                 } catch (InterruptedException e) {
    20                     e.printStackTrace();
    21                 }
    22                 money -= number;
    23                 System.out.println("余额:" + money);
    24             }
    25             return number;
    26         }
    27     }
    28 }
    29 
    30 class BankThread extends Thread {
    31     private Bank bank = null;
    32 
    33     public BankThread(Bank bank) {
    34         this.bank = bank;
    35     }
    36 
    37     @Override
    38     public void run() {
    39         System.out.println("取钱:" + bank.getMoney(400));
    40     }
    41 }

    主方法:

    1         Bank bank=new Bank();
    2         BankThread b1=new BankThread(bank);
    3         b1.start();//柜台取钱
    4         BankThread b2=new BankThread(bank);
    5         b2.start();//ATM机上取钱
    6     

    输出结果:

    余额:100

    取钱:400

    取钱:-3

    同步产生死锁的原因

    当一个线程已经获取了对象1的锁,同时又想获取对象2的锁。而此时另一个线程当前已经持有了对象2的锁,而又想获取对象1的锁。这种互相等待对方释放锁的过程,会导致“死锁”。

     1 class DieThread1 extends Thread {
     2     private Example example = null;
     3 
     4     public DieThread1(Example example) {
     5         super();
     6         this.example = example;
     7     }
     8 
     9     @Override
    10     public void run() {
    11         example.method1();
    12     }
    13 }
    14 
    15 class DieThread2 extends Thread {
    16     private Example example = null;
    17 
    18     public DieThread2(Example example) {
    19         super();
    20         this.example = example;
    21     }
    22 
    23     @Override
    24     public void run() {
    25         example.method2();
    26     }
    27 }
    28 
    29 class Example {
    30     private Object obj1 = new Object();
    31     private Object obj2 = new Object();
    32 
    33     public void method1() {
    34         synchronized (obj1) {
    35             try {
    36                 Thread.sleep(1000);
    37             } catch (InterruptedException e) {
    38                 e.printStackTrace();
    39             }
    40             synchronized (obj2) {
    41                 System.out.println("method1");
    42             }
    43         }
    44     }
    45 
    46     public void method2() {
    47         synchronized (obj2) {
    48             try {
    49                 Thread.sleep(1000);
    50             } catch (InterruptedException e) {
    51                 e.printStackTrace();
    52             }
    53             synchronized (obj1) {
    54                 System.out.println("method2");
    55             }
    56         }
    57     }
    58 }

    主方法:

    1         Example example = new Example();
    2         DieThread1 thread1 = new DieThread1(example);
    3         thread1.start();
    4         DieThread2 thread2 = new DieThread2(example);
    5         thread2.start();

    并没有输出method1和method2。因为都在互相等待对方释放锁,所以应该尽量不要在同步块中嵌套同步块。

  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/wzy330782/p/5469294.html
Copyright © 2011-2022 走看看