当前位置: 首页 > 编程日记 > 正文

JAVA中LOCK

原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html

一.synchronized的缺陷

  我们知道如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

  1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
  2. 线程执行发生异常,此时JVM会让线程自动释放锁。

  那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程一直处于等待状态。因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。

  再举个例子:当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。但是采用synchronized关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。

  因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:

  1. Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
  2. Lock和synchronized有一点非常大的不同,采用 synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

二.java.util.concurrent.locks包下常用的类

下面我们就来探讨一下java.util.concurrent.locks包中常用的类和接口。

  1.Lock

  首先要说明的就是Lock,通过查看Lock的源码可知,Lock是一个接口:

1
2
3
4
5
6
7
8
public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

  下面来逐个讲述Lock接口中每个方法的使用,lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。unLock()方法是用来释放锁的。newCondition()这个方法暂且不在此讲述,会在后面的线程协作一文中讲述。在Lock中声明了四个方法来获取锁,那么这四个方法有何区别呢?

  首先lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。

  由于在前面讲到如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在 try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。通常使用Lock来进行同步 的话,是以下面这种形式去使用的:

1
2
3
4
5
6
7
8
9
Lock lock = ...;
lock.lock();
try{
    //处理任务
}catch(Exception ex){
    
}finally{
    lock.unlock();   //释放锁
}

 tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回 false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。所以,一般情况下通过tryLock来获取锁时是这样使用的:

1
2
3
4
5
6
7
8
9
10
11
12
Lock lock = ...;
if(lock.tryLock()) {
     try{
         //处理任务
     }catch(Exception ex){
        
     }finally{
         lock.unlock();   //释放锁
     
}else {
    //如果不能获取锁,则直接做其他事情
}

  lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。因此lockInterruptibly()一般的使用形式如下:

1
2
3
4
5
6
7
8
9
public void method() throws InterruptedException {
    lock.lockInterruptibly();
    try {  
     //.....
    }
    finally {
        lock.unlock();
    }  
}

 注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。因为本身在前面的文章中讲过单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。

2.ReentrantLock

  ReentrantLock,意思是“可重入锁”。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。下面通过一些实例看具体看一下如何使用ReentrantLock。例子1,lock()的正确使用方法

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Test {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    private Lock lock = new ReentrantLock();    //注意这个地方
    public static void main(String[] args)  {
        final Test test = new Test();
        
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
        
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }  
    
    public void insert(Thread thread) {
        lock.lock();
        try {
            System.out.println(thread.getName()+"得到了锁");
            for(int i=0;i<5;i++) {
                arrayList.add(i);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }finally {
            System.out.println(thread.getName()+"释放了锁");
            lock.unlock();
        }
    }
}

这样就是正确地使用Lock的方法了。例子2,tryLock()的使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Test {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    private Lock lock = new ReentrantLock();    //注意这个地方
    public static void main(String[] args)  {
        final Test test = new Test();
        
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
        
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }  
    
    public void insert(Thread thread) {
        if(lock.tryLock()) {
            try {
                System.out.println(thread.getName()+"得到了锁");
                for(int i=0;i<5;i++) {
                    arrayList.add(i);
                }
            } catch (Exception e) {
                // TODO: handle exception
            }finally {
                System.out.println(thread.getName()+"释放了锁");
                lock.unlock();
            }
        } else {
            System.out.println(thread.getName()+"获取锁失败");
        }
    }
}

 输出结果:

Thread-0得到了锁
Thread-1获取锁失败
Thread-0释放了锁

  例子3,lockInterruptibly()响应中断的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Test {
    private Lock lock = new ReentrantLock();   
    public static void main(String[] args)  {
        Test test = new Test();
        MyThread thread1 = new MyThread(test);
        MyThread thread2 = new MyThread(test);
        thread1.start();
        thread2.start();
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.interrupt();
    }  
    
    public void insert(Thread thread) throws InterruptedException{
        lock.lockInterruptibly();   //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
        try {  
            System.out.println(thread.getName()+"得到了锁");
            long startTime = System.currentTimeMillis();
            for(    ;     ;) {
                if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
                    break;
                //插入数据
            }
        }
        finally {
            System.out.println(Thread.currentThread().getName()+"执行finally");
            lock.unlock();
            System.out.println(thread.getName()+"释放了锁");
        }  
    }
}
class MyThread extends Thread {
    private Test test = null;
    public MyThread(Test test) {
        this.test = test;
    }
    @Override
    public void run() {
        
        try {
            test.insert(Thread.currentThread());
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName()+"被中断");
        }
    }
}

 运行之后,发现thread2能够被正确中断。

3.ReadWriteLock

  ReadWriteLock也是一个接口,在它里面只定义了两个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading.
     */
    Lock readLock();
    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing.
     */
    Lock writeLock();
}

  一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。下面的ReentrantReadWriteLock实现了ReadWriteLock接口。

4.ReentrantReadWriteLock

  ReentrantReadWriteLock里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和writeLock()用来获取读锁和写锁。下面通过几个例子来看一下ReentrantReadWriteLock具体用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Test {
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
    public static void main(String[] args)  {
        final Test test = new Test();
        
        new Thread(){
            public void run() {
                test.get(Thread.currentThread());
            };
        }.start();
        
        new Thread(){
            public void run() {
                test.get(Thread.currentThread());
            };
        }.start();
        
    }  
    
    public void get(Thread thread) {
        rwl.readLock().lock();
        try {
            long start = System.currentTimeMillis();
            
            while(System.currentTimeMillis() - start <= 1) {
                System.out.println(thread.getName()+"正在进行读操作");
            }
            System.out.println(thread.getName()+"读操作完毕");
        } finally {
            rwl.readLock().unlock();
        }
    }
}

 此时打印的结果为:

Thread-0正在进行读操作
Thread-0正在进行读操作
Thread-1正在进行读操作
Thread-0正在进行读操作
Thread-1正在进行读操作
Thread-0正在进行读操作
....
Thread-0读操作完毕 Thread-1读操作完毕

说明thread1和thread2在同时进行读操作。这样就大大提升了读操作的效率。不过要注意的是,如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。

5.Lock和synchronized的选择

  总结来说,Lock和synchronized有以下几点不同:

  1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
  2. synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
  3. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. Lock可以提高多个线程进行读操作的效率。

  在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

三.锁的相关概念介绍

  1.可重入锁

  也叫做递归锁,指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。看下面这段代码就明白了:

1
2
3
4
5
6
7
8
9
class MyClass {
    public synchronized void method1() {
        method2();
    }
    
    public synchronized void method2() {
        
    }
}

 上述代码中的两个方法method1和method2都用synchronized修饰了,假如某一时刻,线程A执行到了method1,此时线程A获取了这个对象的锁,而由于method2也是synchronized方法,假如synchronized不具备可重入性,此时线程A需要重新申请锁。但是这就会造成一个问题,因为线程A已经持有了该对象的锁,而又在申请获取该对象的锁,这样就会线程A一直等待永远不会获取到的锁。而由于synchronized和Lock都具备可重入性,所以不会发生上述现象。

2.可中断锁

  可中断锁:顾名思义,就是可以相应中断的锁。在Java中,synchronized就不是可中断锁,而Lock是可中断锁。如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。在前面演示lockInterruptibly()的用法时已经体现了Lock的可中断性。

3.公平锁

  公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。

 在ReentrantLock中定义了2个静态内部类,一个是NotFairSync,一个是FairSync,分别用来实现非公平锁和公平锁。我们可以在创建ReentrantLock对象时,通过以下方式来设置锁的公平性:

1
ReentrantLock lock = new ReentrantLock(true);

  如果参数为true表示为公平锁,为fasle为非公平锁。默认情况下,如果使用无参构造器,则是非公平锁。

 另外在ReentrantLock类中定义了很多方法,比如:

  • isFair()        //判断锁是否是公平锁
  • isLocked()    //判断锁是否被任何线程获取了
  • isHeldByCurrentThread()   //判断锁是否被当前线程获取了
  • hasQueuedThreads()   //判断是否有线程在等待该锁

  在ReentrantReadWriteLock中也有类似的方法,同样也可以设置为公平锁和非公平锁。不过要记住,ReentrantReadWriteLock并未实现Lock接口,它实现的是ReadWriteLock接口。

4.读写锁

读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。可以通过readLock()获取读锁,通过writeLock()获取写锁。

转载于:https://www.cnblogs.com/wxgblogs/p/5422196.html

相关文章:

【公开课预告】AutoML知多少

5月7日周四19:00&#xff0c;商汤泰坦公开课第010期&#xff0c;论文解读系列课程第二期即将开播&#xff01;我们邀请到商汤科技的4位研究员&#xff0c;分享团队在AutoML方面的一系列研究工作&#xff0c;其中包含CVPR 2020、ICLR 2020等多篇最新论文成果&#xff0c;想要了解…

Linux kernel futex.c的bug导致JVM不可用

JVM死锁导致线程不可用&#xff0c;然后会瞬间起N个线程&#xff0c;当然也是不可用的&#xff0c;因为需要的对象死锁&#xff0c;然后耗尽文件句柄导致外部TCP无法建议拒绝服务&#xff0c;jstack之后就会恢复。 解决办法&#xff1a;替换中间件类库 &#xff0c;比如httpcli…

ruby爬虫综述

http://ihower.tw/blog/archives/2941一个ruby爬虫的例子http://hi.baidu.com/anspider/blog/item/9da210425a0e4e179213c6fb.html

Exchange 2016集成ADRMS系列-12:域内outlook 2010客户端测试

接下来&#xff0c;我们来到域内安装了office 2010的机器上进行测试。 首先我们在客户端上强制刷新组策略&#xff0c;把我们刚才设置的策略刷新下来。 然后我们可以运行gpresult /h result.html来看看策略是不是已经下来了。 策略下来之后&#xff0c;我们打开客户端上面的out…

在Linux下编写Daemon

在Linux下编写Daemon 转自&#xff1a;http://blog.163.com/prevBlogPerma.do?hostmanyhappy163&srl1644768312010718111142260&modeprev 在Linux&#xff08;以Redhat Linux Enterprise Edition 5.3为例&#xff09;下&#xff0c;有时需要编写Service。Service也是…

JVM虚拟机参数配置官方文档

JDK8 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/index.html JDK7 https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html 官方博客 https://blogs.or…

在Rust代码中编写Python是种怎样的体验?

作者 | Mara Bos&#xff0c;Rust资深工程师译者 | Arvin&#xff0c;编辑 | 屠敏来源 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;大约一年前&#xff0c;我发布了一个名为inline-python&#xff08;https://crates.io/crates/inline-python&#xff09;的Rust类库…

Docker配置指南系列(二):指令集(二)

pause: 停止一个容器的所有进程语法&#xff1a;ocker pause CONTAINER [CONTAINER...] port: 列出容器的端口映射&#xff0c;或者查看指定开放端口的NAT映射语法&#xff1a;docker port [--help] CONTAINER [PRIVATE_PORT[/PROTO]] ps: 列出容器语法&#xff1…

无需训练RNN或生成模型,我写了一个AI来讲故事

作者 | Andre Ye译者 | 弯月出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;这段日子里&#xff0c;我们都被隔离了&#xff0c;就特别想听故事。然而&#xff0c;我们并非对所有故事都感兴趣&#xff0c;有些人喜欢浪漫的故事&#xff0c;他们肯定不喜欢…

Java字节码instrument研究

MyAgent项目 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

怎样保持良好的心态

有一位朋友有一次气冲冲的跟我说&#xff1a;“气死我了&#xff01;我刚刚发现我一位员工出了错&#xff0c;令产品出现了质量的问题&#xff0c;我修理了他一顿。。。 我问&#xff1a;”你认为你的生产流程里面可能一点错误都没有吗&#xff1f;“ 他说&#xff1a;”应该不…

web编程速度大比拼(nodejs go python)(非专业对比)

C10K问题的解决&#xff0c;涌现出一大批新框架&#xff0c;或者新语言&#xff0c;那么问题来了:到底谁最快呢&#xff1f;非专业程序猿来个非专业对比。 比较程序&#xff1a;输出Hello World&#xff01; 测试程序&#xff1a;siege –c 100 –r 100 –b 例子包括&#xff1…

linux邮件服务

邮件服务要求:l 能够构建完整的邮件系统 能够正确设置DNS邮件服务器记录 l 能够配置sendmail服务器 设置客户端软件使用邮件服务器 准备工作&#xff1a; l 主机名&#xff1a;srv.benet.com /etc/sysconfig/network <永久的> l 域名 正向区域 bt.com完成NDS的…

MaskFlownet:基于可学习遮挡掩模的非对称特征匹配丨CVPR 2020

来源 | 微软研究院AI头条&#xff08;ID: MSRAsia&#xff09;编者按&#xff1a;在光流预测任务中&#xff0c;形变带来的歧义与无效信息会干扰特征匹配的结果。在这篇 CVPR 2020 Oral 论文中&#xff0c;微软亚洲研究院提出了一种可学习遮挡掩模的非对称特征匹配模块 &#x…

GDB调试--以汇编语言为例

#rpm -qa |grep gdb 下载&#xff1a; 安装 #tar -zxvf #./configure #make 使用GDB 以汇编语言调试为例 汇编语言实现CPUID指令 CPUID cpuid是Intel Pentinum以上级CPU内置的一个指令&#xff08;486级以下的CPU不支持&#xff09;&#xff0c;他用于识别某一类型…

汇编语言系统调用过程

以printf为例&#xff0c;详细解析一个简单的printf调用里头&#xff0c;系统究竟做了什么&#xff0c;各寄存器究竟如何变化。 如何在汇编调用glibc的函数&#xff1f;其实也很简单&#xff0c;根据c convention call的规则&#xff0c;参数反向压栈&#xff0c;call&#xf…

switch语句中在case块里声明变量会遇到提示“Expected expression before...的问题

switch语句中在case块里声明变量会遇到提示“Expected expression before..."的问题 例如在如下代码中 1case constant:2 int i 1;3 int j 2;4 self.sum i j;5 break;GCC在case语句之后的第一行中声明变量时遇到问题。 这时需要在case块两端添加花括号&am…

帮AI体检看病一条龙服务,阿里发布“AI安全诊断大师”

如同一些出生免疫力就有缺陷的人一样&#xff0c;AI也存在免疫力缺陷。基于从源头打造安全免疫力的新一代安全架构理念&#xff0c;最近&#xff0c;阿里安全研究发布了一项核心技术“AI安全诊断大师”&#xff0c;可对AI模型全面体检&#xff0c;“看诊开方”&#xff0c;让AI…

Spring学习总结(7)——applicationContext.xml 配置文详解

web.xml中classpath:和classpath*: 有什么区别? classpath&#xff1a;只会到你的class路径中查找找文件; classpath*&#xff1a;不仅包含class路径&#xff0c;还包括jar文件中(class路径)进行查找. 存放位置&#xff1a; 1&#xff1a;src下面 需要在web.xml中定义如下&…

GDB查看栈信息

栈&#xff1a;是程序存放数据内存区域之一&#xff0c;特点是LIFO&#xff08;后进先出&#xff09;。 PUSH&#xff1a;入栈 POP&#xff1a;出战 使用场景&#xff1a; 1.保存动态分配的自动变量使用栈 2.函数调用时&#xff0c;用栈传递函数参数&#xff0c;半寸返回地址…

数据库学习之路

今天迎来入冬的第二场雪&#xff0c;闲来无事就整理了下总结下工作以来所有数据库方面的书籍和资料&#xff0c;发现了不少&#xff0c;很多已经读过或者正在读的书籍&#xff0c;oracle真的很强大&#xff0c;直到现在发现才入门的水平&#xff0c;当然很多书读一遍是不行的&a…

为什么铺天盖地都是Python的广告?

最近&#xff0c;知乎关于Python有一个热议问题&#xff1a; 甚至在抖音上&#xff0c;笔者有一次还看到Python占领了热搜&#xff01;应该有很多不懂技术的吃瓜群众也被Python的热度炒懵了……但是&#xff0c;Python真的值得学吗&#xff1f;真的值得花这么多钱去学吗&#x…

python3正则表达式符号和用法

转载于:https://www.cnblogs.com/wumac/p/5441322.html

从寄存器看I386和x64位中函数调用中参数传递

x86_64基本使用寄存器存储函数参数&#xff0c;寄存器不够才入栈&#xff1b; 而i386将所有参数保存在栈上&#xff0c;通过gcc的扩展功能__attribute__((regparm()))即可实现部分参数的寄存器传递。 调试语法&#xff1a; --《深入理解计算机系统(原书第2版)》 代码 #incl…

转:去掉Flex4生成的SWF加载时的进度条

方法一&#xff1a; <?xml version"1.0" encoding"utf-8"?> <s:Application xmlns:fx"http://ns.adobe.com/mxml/2009" xmlns:s"library://ns.adobe.com/flex/spark" xmlns:mx"library://ns.adobe.com/f…

饿了么交易系统5年演化史

作者 | 挽晴来源 | 阿里巴巴中间件&#xff08;ID&#xff1a;Aliware_2018&#xff09;个人简介:2014年12月加入饿了么&#xff0c;当时参与后台系统的研发(WalisJavis>Walle)&#xff0c;主要面向客服和BD。2015年5月开始接触订单系统的研发&#xff0c;7月负责订单研发组…

Python迁移MySQL数据到MongoDB脚本

MongoDB是一个文档数据库&#xff0c;在存储小文件方面存在天然优势。随着业务求的变化&#xff0c;需要将线上MySQL数据库中的行记录&#xff0c;导入到MongoDB中文档记录。 一、场景&#xff1a;线上MySQL数据库某表迁移到MongoDB&#xff0c;字段无变化。 二、Python模块&am…

使用valgrind分析C程序调用线路图

Valgrind可以检测内存泄漏和内存违例&#xff0c;但是用Valgrind生成的日志信息结合kcachegrind就可以查看C程序的执行线路图&#xff0c;调用时间&#xff0c;是做性能优化和查看代码的非常好的工具。 1.下载安装 Valgrind 安装 到www.valgrind.org下载最新版valgrind # wg…

纯CSS实现蓝色圆角下拉菜单

代码简介&#xff1a; 这个菜单没有使用任何的图片&#xff0c;完全是用CSS实现的&#xff0c;包括圆角效果也同样是&#xff0c;而且还考虑了多浏览器的兼容性&#xff0c;可以说非常不错&#xff0c;既兼容性好&#xff0c;又外观漂亮&#xff0c;下拉导航菜单目前比较流行&a…

生产型机器学习已经没那么困难了?

作者 | Caleb Kaiser译者 | 香槟超新星出品 | CSDN&#xff08;ID:CSDNnews&#xff09;封面图源自视觉中国在软件工程的诸多领域内&#xff0c;生产用例是相当标准化的。以Web开发为例&#xff0c;要在Web应用中实现身份认证&#xff0c;你不会去创造一个数据库&#xff0c;自…