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

  • 相关阅读:
    shell脚本的分发,测试,查看
    shell 脚本获取cpu信息(转载)
    shell 脚本编写之获取字符串长度(转载)
    service
    关于Linux安装中NAT模式和桥接模式的区别详解(转载)
    kdj
    pod 详解
    k8s基本概念,资源对象
    AliOS Things添加环境变量
    子函数通过一级指针访问二维数组
  • 原文地址:https://www.cnblogs.com/wzy330782/p/5469294.html
Copyright © 2011-2022 走看看