java并发编程(二十四)-并发安全之活锁,线程饥饿

什么是活锁?

多线程环境下,线程在尝试拿锁的机制中,发生多个线程之间互相谦让,不断发生拿锁,释放锁的过程。

模拟银行转账的业务:

实体类:

package com.caojiulu;

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

/**
 *@author caojiulu
 *
 *类说明:用户账户的实体类
 */
public class UserAccount {
    //private int id;
    private final String name;//账户名称
    private int money;//账户余额

    //显示锁
    private final Lock lock = new ReentrantLock();

    public Lock getLock() {
        return lock;
    }

    public UserAccount(String name, int amount) {
        this.name = name;
        this.money = amount;
    }

    public String getName() {
        return name;
    }

    public int getAmount() {
        return money;
    }

    @Override
    public String toString() {
        return "UserAccount{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }

    //转入资金
    public void addMoney(int amount){
        money = money + amount;
    }

    //转出资金
    public void flyMoney(int amount){
        money = money - amount;
    }
}

定义接口:

package com.caojiulu.service;

import com.caojiulu.UserAccount;

/**
 *@author caojiulu
 *
 *类说明:银行转账动作接口
 */
public interface ITransfer {
	/**
	 * 
	 * @param from 转出账户
	 * @param to 转入账户
	 * @param amount 转账金额
	 * @throws InterruptedException
	 */
    void transfer(UserAccount from, UserAccount to, int amount) 
    		throws InterruptedException;
}

接口实现类:

package com.caojiulu.service;

import java.util.Random;

import com.caojiulu.UserAccount;
import com.caojiulu.SleepTools;

/**
 *@author caojiulu
 *
 *类说明:测试活锁
 */
public class SafeOperateToo implements ITransfer {

    @Override
    public void transfer(UserAccount from, UserAccount to, int amount)
            throws InterruptedException {
    	Random r = new Random();
    	while(true) {
    		if(from.getLock().tryLock()) {
    			try {
    				System.out.println(Thread.currentThread().getName()
    						+" get "+from.getName());
    				if(to.getLock().tryLock()) {
    					try {
    	    				System.out.println(Thread.currentThread().getName()
    	    						+" get "+to.getName());    						
    						//两把锁都拿到了
    	                    from.flyMoney(amount);
    	                    to.addMoney(amount);
    	                    break;
    					}finally {
    						to.getLock().unlock();
    					}
    				}
    			}finally {
    				from.getLock().unlock();
    			}
    		}
    		//SleepTools.ms(r.nextInt(10)); //这里注释掉了
    	}
    }
}

测试类:

package com.caojiulu

import com.caojiulu.service.ITransfer;
import com.caojiulu.SafeOperateToo;


/**
 *@author caojiulu
 *
 *类说明:模拟支付公司转账的动作
 */
public class PayCompany {

	/*执行转账动作的线程*/
    private static class TransferThread extends Thread{

        private String name;//线程名字
        private UserAccount from; 
        private UserAccount to; 
        private int amount;
        private ITransfer transfer; //实际的转账动作

        public TransferThread(String name, UserAccount from, UserAccount to,
                              int amount, ITransfer transfer) {
            this.name = name;
            this.from = from;
            this.to = to;
            this.amount = amount;
            this.transfer = transfer;
        }


        public void run(){
            Thread.currentThread().setName(name);
            try {
                transfer.transfer(from,to,amount);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        PayCompany payCompany = new PayCompany();
        UserAccount zhangsan = new UserAccount("zhangsan",20000);
        UserAccount lisi = new UserAccount("lisi",20000);
        ITransfer transfer = new SafeOperateToo();
        TransferThread zhangsanToLisi = new TransferThread("zhangsanToLisi"
                ,zhangsan,lisi,2000,transfer);
        TransferThread lisiToZhangsan = new TransferThread("lisiToZhangsan"
                ,lisi,zhangsan,4000,transfer);
        zhangsanToLisi.start();
        lisiToZhangsan.start();

    }

}

运行结果:

这就是因为//SleepTools.ms(r.nextInt(10));发生多个线程之间互相谦让,不断发生拿锁,释放锁的过程。

解决办法:

每个线程休眠随机数,错开拿锁的时间。

 

线程饥饿:

非公平锁的抢占机制就会可能导致饥饿,线程优先级比较低的时候容易产生,当T1线程占用了资源A,T2,T3,T4。。。都在等待锁的释放,当锁释放的时候,T3抢到了资源,之后又释放锁,T4抢到了资源。。。T2 总是抢不到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值