并发编程原理

原创
2020/04/12 09:37
阅读数 567

java多线程的锁主要是为了干嘛?

保证线程同步执行,如果没有锁

A线程,B线程

a(){

int i;

}

A和B线程都会访问到a(),同时对a变量做修改,就会造成脏读

如果能够保证A线程,B线程的执行顺序,当一个线程做修改的时候,另一个线程是不能进入这个方法的,那么问题解决可了,也就是让多线程同步执行

wait,notify ,synchronized,ReentrantLock都可以

模拟一些同步的思路

volatile int state = 0;//这个是标识锁的状态的,是否上锁了,这里

void lock(){

while(!compareAndSet(0,1)){//CAS比较即交换,当传入值为0,则把传入值改为1,否则,输出为原值。

     }
    
}
package com.liuyuan.book;

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

/**
 * Created by Administrator on 2020/4/12.
 */
public class Test {
    static Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        new Thread(()->{
            testsync();
            System.out.println("t1......");
        },"t1").start();


        new Thread(()->{
            System.out.println("t2......");
        },"t2").start();
    }
    private static void  testsync(){
        lock.lock();
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}

t2......
t1......

或者

t1......

t2......

 

有synchonized关键字,为什么还要用reentrantlock呢?

start()方法,调用了java jdk自带的c++方法

private native void start0();

这个方法调用openjdk,再调用c,再调用操作系统,启动线程

jvm 的t1线程实际上对应的是操作系统的线程 

调用操作系统执行的函数,是重量级锁

cpu内核态(线程阻塞,资源不能被访问)--->切换用户态,线程能执行,资源能访问

jdk1.6及之前,是在操作系统级别解决线程同步问题

jdk1.7尽量 在jvm层面上保证线程同步

Doug lea 这个大佬觉得线程同步要进行操作系统和jvm层面操作,很重,juc下面的很多都是这位写的,很不错,不过sun公司看不惯了,synchonized才是正统啊,接着做优化

这里提下concurrenthashmap,jdk1.7用的segment分段锁+reentrantlock,锁粒度更细

jdk1.8用的cas+synchonized ,这也是为什么又重新用了sync

volatile int state = 0;//这个是标识锁的状态的,是否上锁了,这里

void lock(){
//自旋

while(!compareAndSet(0,1)){//CAS比较即交换,当传入值为0,则把传入值改为1,否则,输出为原值。

     }
    
}

自旋消耗cpu性能,没有竞争到锁的线程,会一直占用cpu资源进行cas操作

这样我们就有一个优化的思路,让未得到锁的线程,让出cpu

接下来看如下的代码

当获取锁的时候,先判断state是否为0,若为0,则说明无线程占用锁,那么就通过cas操作,将状态改为1,改成功了,就可以进行操作

若为1,状态不会更改,不能进行操作,获取不到锁。

 

对于说公平所和非公平锁的区别在哪呢?

 

在于是否看队列中有等待的线程,如果有,那么就排队,fifo先进先出

如果没有排队的,说明就只有当前这个线程需要抢占资源,直接调用cas,更改状态就可以了 

具体细节后续补充 

 

mysql 的读写操作都是悲观锁,乐观锁是自己加版本号来控制的

自旋锁

充入锁  

公平锁  

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部