EchoDemo's Blogs

Java中的多线程编程

1、线程同步

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

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

(2)对于同步,一般而言在Java中需要完成两个操作:把竞争访问的资源表示为private;同步那些访问资源的代码,使用synchronized关键字修饰方法或者代码块。当synchronized方法执行完或者发生异常时会自动释放锁。

2、举例

(1)案例介绍

某银行账号上有500元存款,一个人拿着存折去取钱,同时另一个人拿着银行卡去ATM机上取钱,各自取钱400元。要求取钱的过程中不能出现资源竞争:比如400元被取出两次、银行卡的账目不能小于0等。

(2)案例实现

package com.iotek.synchronize;

public class BankDemo {

    public static void main(String[] args) {
        Bank bank1 = new Bank();
        BankThread bankThread = new BankThread(bank1);
        bankThread.start();//柜台取钱
        BankThread bankThread2 = new BankThread(bank1);
        bankThread2.start();//ATM机取钱
    }
}

class Bank{
    private int money = 500;
    private Object object = new Object();//锁这个对象也可以实现,因为任何对象都只有一个锁。

    /*取钱的方法,返回取钱的数目
    当一个线程去调用同步方法的时候,这个线程就调用了当前对象的锁。其他线程则等待*/
    public int getMoney(int number) throws InterruptedException{
        synchronized(this){
            if(number < 0)
                return -1;
            else if(money < 0)
                return -2;
            else if(number - money >0)
                return -3;
            else{
                Thread.sleep(1000);
                money-=number;
                System.out.println("账户余额:" + money);
            }
            return number;
        }
    }
}

class BankThread extends Thread{
    private Bank bank = null;
    public BankThread(Bank bank){
        this.bank = bank;
    }
    @Override
    public void run(){
        try {
            System.out.println("取钱:"+bank.getMoney(400));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、同步产生死锁

(1)同步产生死锁的原因:当一个线程已经获取了对象1的锁,同时又想获取对象二的锁。而此时另一个线程当前已经持有了对象二的锁,而又想获取对象一的锁。这中相互等待对方释放锁的过程,会导致“死锁”。

(2)死锁举例

package com.iotek.synchronize;

public class DieThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        Example example = new Example();
        DieThread thread1 = new DieThread(example);
        thread1.start();
        DieThread1 thread2 = new DieThread1(example);
        thread2.start();
    }
}

class Example{
    private Object obj1 = new Object();
    private Object obj2 = new Object();

    public void method1() throws InterruptedException{//先占用对象1,再请求对象2.
        synchronized (obj1) {
            Thread.sleep(1000);
            synchronized (obj2) {
                System.out.println("method1");
            }
        }
    }

    public void method2() throws InterruptedException{//先占用对象2,再请求对象1.
        synchronized (obj2) {
            Thread.sleep(1000);
            synchronized (obj1) {
                System.out.println("method2");
            }
        }
    }
}

class DieThread extends Thread{//死亡进程1
    private Example example = null;

    public DieThread(Example example) {
        super();
        this.example = example;
    }

    @Override
    public void run(){
        try {
            example.method1();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class DieThread1 extends Thread{//死亡进程2
    private Example example = null;

    public DieThread1(Example example) {
        super();
        this.example = example;
    }

    @Override
    public void run(){
        try {
            example.method2();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
🐶 您的支持将鼓励我继续创作 🐶
-------------本文结束感谢您的阅读-------------