Java并发编程4 —— 对象锁的同步和异步

同步和异步

当访问共享资源时,我们为了保证线程安全,让每个线程在操作共享变量前读到的都是正确的值,必须同步地执行代码,即每个线程方法执行完毕后才能继续。

而异步则不需要等待其他线程的方法执行完毕,可以立刻执行,这里不涉及对共享资源的操作。

对象锁的同步和异步

直接上代码吧。

import static java.lang.Thread.sleep;

public class SyncAndAsyn {
    public static void main(String[] args) {
        Exec exec = new Exec();
        Run1 run1 = new Run1(exec);
        Run2 run2 = new Run2(exec);
        Thread t1 = new Thread(run1);
        Thread t2 = new Thread(run2);
        t1.start();
        t2.start();
    }
}

class Exec{
    public synchronized void func1(){
        System.out.println("func 1: " + System.currentTimeMillis());
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void func2(){
        System.out.println("func 2: " + System.currentTimeMillis());
    }
}

class Run1 implements Runnable{
    private Exec exec;

    public Run1(Exec exec){
        this.exec = exec;
    }

    @Override
    public void run() {
        exec.func1();
    }

}

class Run2 implements Runnable{
    private Exec exec;

    public Run2(Exec exec){
        this.exec = exec;
    }

    @Override
    public void run() {
        exec.func2();
    }
}

在Exec类中,func1和func2两个方法都定义为Sunchronized,两个线程t1和t2分别执行func1和func2。这是两个线程执行两个不同的方法,应该是异步执行的吧,然而输出如下:

func 1: 1537014956574
func 2: 1537014958576

两个方法的执行时间点刚好相差了两秒,也就是说线程t2受到了线程t1执行func1方法时的sleep(2000)的影响,等t1执行func1完毕后才进入到func2里。

如果把func2定义为非Synchronized会怎么样呢。

import static java.lang.Thread.sleep;

public class SyncAndAsyn {
    public static void main(String[] args) {
        Exec exec = new Exec();
        Run1 run1 = new Run1(exec);
        Run2 run2 = new Run2(exec);
        Thread t1 = new Thread(run1);
        Thread t2 = new Thread(run2);
        t1.start();
        t2.start();
    }
}
class Exec{
    public synchronized void func1(){
        System.out.println("func 1: " + System.currentTimeMillis());
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void func2(){
        System.out.println("func 2: " + System.currentTimeMillis());
    }
}

class Run1 implements Runnable{
    private Exec exec;

    public Run1(Exec exec){
        this.exec = exec;
    }

    @Override
    public void run() {
        exec.func1();
    }

}

class Run2 implements Runnable{
    private Exec exec;

    public Run2(Exec exec){
        this.exec = exec;
    }

    @Override
    public void run() {
        exec.func2();
    }
}

输出:

func 1: 1537016097712
func 2: 1537016097712

此时两个线程同时执行了func1和func2两个方法。

产生这种现象的原因是创建两个线程的Runnable对象时使用了同一个Exec对象,也就是说虽然是两个线程,但是它们执行的func1和func2是同一个对象的两个方法。而这里不存在static方法和变量,所以给func1或func2加了同步锁,实际上就是给Exec对象加了锁。两个线程访问同一个加了锁的对象,当然会同步执行。

那么另一个问题来了,为什么func1为Synchronized、func2为非Synchronized时,两个线程没有同步执行?这是因为虽然加了对象锁,但是这个锁只对对象内的Synchronized方法有效。这就好比一个超市里只有一个货架和一个收银台。同一时刻只能有一个人在收银台结账,所以结账的方法是Synchronized的,但是同时可以有很多人在货架前挑选商品(忽略最大容纳人数等极端情况),那么挑选商品的方法就不是Synchronized的。

    原文作者:java锁
    原文地址: https://blog.csdn.net/qq_25246305/article/details/82717475
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞