线程锁(四)
2021-03-25 06:26
标签:argument nal 不能 tor err 如何 加锁 static ali 前面篇幅讲了很多理论及原理性东西,今天想了想,来点现实场景的东西把前面的内容串一串 通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。 进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞。 信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A 发的消息,可以看出进程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。
产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。 下面就定义来演示一个死锁场景的例子: 如下图,死锁条件产生了,下面死锁产生的条件就是互斥产生的,想要破坏死锁只用破坏死锁的四大条件的其中一个就可以,下面我们就上面代码优化下,破坏占有且等待这个条件来破坏。 我们增加一个类,专门用来分配资源 修改原有的Deadlock类 自己运行下会发现死锁解决了,上面我们是破坏了占有且等待这个条件解决了死锁,下面我们就不可抢占这个条件来解决死锁问题,我们利用Lock的属性来破坏,将Deadlock代码再修改一次(Lock我想在下个篇幅中具体讲) 最后我们再循环等待条件破坏死锁 如果我们想要线程的结果对主线程可见我们可以用join,看下图结果我们一定有问题,为啥加了join就对主线程可见,下面我们就join的原理讲解下 我们点击t.join();看下join方法做了什么事情,看到下面源码我们发现一个关健字wait,如果看过我前面写的文章朋友应该很快想到他的原理就是阻塞,想到了阻塞那就一定有唤醒,那我们想,唤醒阻塞代码的地方会在哪里呢。 一个线程在run方法执行结束时就代表一个线程的终止,线程终止会调用C的javaThread:: exit方法;在这个方法里面会有个清理的方法叫ensure_join(this);这个方法会唤醒阻塞方法下的线程; ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。说白点就是实际上一种线程隔离机制,也是为了保证在多线程环境下对于共享变量的访问的安全性。下面我们就一个例子说明下 上面的例子我们发现每个线程间存在干扰问题,而且有的线程取的值还是相同的,如果我们想做到线程问的隔离,那我们就可以用到ThreadLocal,下图结果我们发现做到线程的隔离 下面我们就ThreadLocal是如何实现的,我们进入源码 在源码的set方法 点进去好像也没有啥东西 那我们就行先暂时跳过,我们走if逻辑,我们第一次进来map是空的所有走createMap 下面这段代码对每个线程都会创建一个存储,这就做到了线程间的隔离,而且下面源码中用到了hash计算及线性探测,如果我要全写完的话要化更多的时间,而且跟我要讲的线程主题偏远了,后面如果有时间,我再单独就这块内容的线性探测深入讲解下 线程锁(四) 标签:argument nal 不能 tor err 如何 加锁 static ali 原文地址:https://www.cnblogs.com/xing1/p/13768704.html一. 死锁产生的原因
1) 系统资源的竞争
2) 进程推进顺序非法
3) 死锁产生的必要条件
public class Transfer {
private String accountName;
private int balance;
public Transfer(String accountName, int balance) {
this.accountName = accountName;
this.balance = balance;
}
public void debit(int amount){ //更新转出方的余额
this.balance-=amount;
}
public void credit(int amount){ //更新转入方的余额
this.balance+=amount;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
public class Deadlock implements Runnable{
private Transfer fromAccount; //转出账户
private Transfer toAccount; //转入账户
private int amount; //转入金额
public Deadlock(Transfer fromAccount, Transfer toAccount, int amount) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance() >= amount) {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
//转出账户的余额
System.out.println(fromAccount.getAccountName() + "->" + fromAccount.getBalance());
//转入账户的余额
System.out.println(toAccount.getAccountName() + "-->" + toAccount.getBalance());
}
}
public static void main(String[] args) throws InterruptedException {
Transfer fromAccount=new Transfer("用户A",100000);
Transfer toAccount=new Transfer("用户B",300000);
Thread a =new Thread(new Deadlock(fromAccount,toAccount,10));
Thread b=new Thread(new Deadlock(toAccount,fromAccount,30));
a.start();
b.start();
}
}
public class Allocator {
private List
public class Deadlock implements Runnable{
private Transfer fromAccount; //转出账户
private Transfer toAccount; //转入账户
private int amount; //转入金额
Allocator allocator;
public Deadlock(Transfer fromAccount, Transfer toAccount, int amount,Allocator allocator) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
this.allocator=allocator;
}
@Override
public void run() {
while(true){
//锁力度调大,在if层面
if (allocator.apply(fromAccount,toAccount)) {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance() >= amount) {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
//转出账户的余额
System.out.println(fromAccount.getAccountName() + "->" + fromAccount.getBalance());
//转入账户的余额
System.out.println(toAccount.getAccountName() + "-->" + toAccount.getBalance());
}
}
public static void main(String[] args) throws InterruptedException {
Transfer fromAccount=new Transfer("用户A",100000);
Transfer toAccount=new Transfer("用户B",300000);
Allocator allocator=new Allocator();
Thread a =new Thread(new Deadlock(fromAccount,toAccount,10,allocator));
Thread b=new Thread(new Deadlock(toAccount,fromAccount,30,allocator));
a.start();
b.start();
}
}
public class Deadlock1 implements Runnable{
private Transfer fromAccount; //转出账户
private Transfer toAccount; //转入账户
private int amount; //转入金额
Lock fromLock=new ReentrantLock();
Lock toLock=new ReentrantLock();
public Deadlock1(Transfer fromAccount, Transfer toAccount, int amount) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
@Override
public void run() {
while(true){
if (fromLock.tryLock()) {
if (toLock.tryLock()) {
if (fromAccount.getBalance() >= amount) {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
//转出账户的余额
System.out.println(fromAccount.getAccountName() + "->" + fromAccount.getBalance());
//转入账户的余额
System.out.println(toAccount.getAccountName() + "-->" + toAccount.getBalance());
}
}
public static void main(String[] args) throws InterruptedException {
Transfer fromAccount=new Transfer("用户A",100000);
Transfer toAccount=new Transfer("用户B",300000);
Thread a =new Thread(new Deadlock1(fromAccount,toAccount,10));
Thread b=new Thread(new Deadlock1(toAccount,fromAccount,30));
a.start();
b.start();
}
}
public class Deadlock2 implements Runnable{
private Transfer fromAccount; //转出账户
private Transfer toAccount; //转入账户
private int amount; //转入金额
public Deadlock2(Transfer fromAccount, Transfer toAccount, int amount ) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
@Override
public void run() {
Transfer left=null;
Transfer right=null;
//控制加锁顺序
if (fromAccount.hashCode()>toAccount.hashCode()){
left=toAccount;
right=fromAccount;
}
while(true){
synchronized (left) {
synchronized (right) {
if (fromAccount.getBalance() >= amount) {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
//转出账户的余额
System.out.println(fromAccount.getAccountName() + "->" + fromAccount.getBalance());
//转入账户的余额
System.out.println(toAccount.getAccountName() + "-->" + toAccount.getBalance());
}
}
public static void main(String[] args) throws InterruptedException {
Transfer fromAccount=new Transfer("用户A",100000);
Transfer toAccount=new Transfer("用户B",300000);
Allocator allocator=new Allocator();
Thread a =new Thread(new Deadlock(fromAccount,toAccount,10,allocator));
Thread b=new Thread(new Deadlock(toAccount,fromAccount,30,allocator));
a.start();
b.start();
}
}
二.Thread.join
//首先源码中方法中加了锁
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis
三.ThreadLocal
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//有Map最先想到的是存储,我们点进去看下
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
//ThreadLocal.ThreadLocalMap threadLocals = null;}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal> firstKey, Object firstValue) {
//有兴趣可以点进看下Entry;这一步是初始化一个长度
table = new Entry[INITIAL_CAPACITY];
//这里面i的值其实就是一个下标,这里里其实就是用hash计算出下标位置,然后将数据存储起来
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}