Java多线程编程基础

1 隐式加锁


下面是一个Account类,这里看成是线程访问的资源。

package com.lin.test;

public class Account {
    
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
    
    public void deposit(double amount)
    {
        double newBalance = balance + amount;
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        };
        balance = newBalance;
    }
    
    public void withdraw(double amount)
    {
        balance = balance - amount;
    }

}


现在有多个线程访问这个对象

public class Test {
    
    private static Account account = new Account();

    public static void main(String[] args) {
        
        ExecutorService executor = Executors.newCachedThreadPool();
        
        for(int i = 0;i<100;i++)
        {
            executor.execute(new Runnable() {
                
                @Override
                public void run() {
                    account.deposit(1);
                }
            });
        }
        executor.shutdown();
        
        while(!executor.isTerminated()){}
        
        System.out.println("Balance :"+account.getBalance());
    }
}


上面的代码是一共有100个线程向account的balance加1,结果应该是100的,但是由于多个线程竞争资源,导致balance的值是2.0.

那么多线程编程里面可以用synchronized关键字来给资源加锁。

public synchronized void  deposit(double amount)
    {
        double newBalance = balance + amount;
        try {
            Thread.sleep(5);
            balance = newBalance;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


给deposit加上synchronized关键字后就使该方法同步,即隐式加锁。


2 显式加锁

隐式加锁不方便协调线程的工作,为了能更好地控制线程,显示加锁比较好。

package com.lin.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {
    
    private double balance;
    
    private static Lock lock = new ReentrantLock();//创建一个锁

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
    
    public void  deposit(double amount)
    {
        lock.lock();//获得锁
        
        double newBalance = balance + amount;
        try {
            Thread.sleep(5);
            balance = newBalance;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally{
            lock.unlock();//释放锁
        }
    }
    
    public void withdraw(double amount)
    {
        balance = balance - amount;
    }

}


这时效果解决资源竞争的效果和隐式加锁是一样的。


3 让多个线程协调工作

现在,如果我们有一个这种需求,我们向账户里取钱时,如果钱不够,那么就等待,直到向账户里存钱了并且钱足够,才继续取钱。线程协调中需要Condition的帮助,重新修改deposite和withdraw方法。

package com.lin.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {
    
    private double balance;
    
    private static Lock lock = new ReentrantLock();//创建一个锁
    
    private static Condition condition = lock.newCondition();//创建一个条件

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
    
    /**
     * 存钱.
     * @param amount
     */
    public void  deposit(double amount)
    {
        lock.lock();//获得锁
        
        double newBalance = balance + amount;
        try {
            
            Thread.sleep(5);
            
            balance = newBalance;
            System.out.println("存入钱数:"+amount+"\t"+"余额:"+getBalance());
            
            condition.signalAll();//唤醒所有等待的线程
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally{
            lock.unlock();//释放锁
        }
    }
    
    /**
     * 取钱.
     * @param amount
     */
    public void withdraw(double amount)
    {
        lock.lock();
        
        try {
            while(balance < amount)
            {
                System.out.println("钱不够了,正在等待存钱。。。");
                condition.await();//让当前的线程进入等待状态,当其他线程signal或signalAll时唤醒该线程
            }
            
            balance = balance - amount;
            System.out.println("取出钱数:"+amount+"\t余额:"+getBalance());
            
        } catch (Exception e) {
            
            e.printStackTrace();
        }
        finally{
            lock.unlock();
        }
    }

}


然后现在让两个线程去访问资源。

package com.lin.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    
    private static Account account = new Account();

    public static void main(String[] args) {
        
//        ExecutorService executor = Executors.newCachedThreadPool();
//        
//        for(int i = 0;i<100;i++)
//        {
//            executor.execute(new Runnable() {
//                
//                @Override
//                public void run() {
//                    account.deposit(1);
//                }
//            });
//        }
//        executor.shutdown();
//        
//        while(!executor.isTerminated()){}
//        
//        System.out.println("Balance :"+account.getBalance());
        
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        //deposit
        executor.execute(new Runnable() {
            
            @Override
            public void run() {
                
                try {
                    int i = 0;
                    while(i<10)
                    {
                        i++;
                        account.deposit(Math.random()*10 + 1);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        
        //withdraw
        executor.execute(new Runnable() {
            
            @Override
            public void run() {
                
                try {
                    int i=0;
                    while(i<10)
                    {
                        i++;
                        account.withdraw(Math.random()*10 + 1);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        
        executor.shutdown();
        
        System.out.println("-----------------------------------------");
    }
}


运行结果

Java多线程编程基础_第1张图片

你可能感兴趣的:(java)