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。因为都在互相等待对方释放锁,所以应该尽量不要在同步块中嵌套同步块。

  • 相关阅读:
    QQ企业邮箱+Spring+Javamail+ActiveMQ(发送企业邮件)
    Notepad++使用图解
    Sublime Text 2安装图解
    IDE UltraEdit 图文激活+安装教程
    光猫与普通的家用猫
    通过Java Api与HBase交互(转)
    HBase配置性能调优(转)
    HBase Java API类介绍
    hbase shell基础和常用命令详解(转)
    HBase体系结构(转)
  • 原文地址:https://www.cnblogs.com/wzy330782/p/5469294.html
Copyright © 2011-2022 走看看