1.2 多个线程多个锁

概述

多个线程中,如果每个线程操作的对象是不同的,那么就会为每个线程产生一把锁,这个时候,在不同的线程中,锁是不起作用的。

代码

MultiThread.java

public class MultiThread {

    private int num = 0;

    public synchronized void printNum(String tag) throws InterruptedException {
        if (tag.equals("a")) {
            num = 100;
            System.out.println("tag a, set num over!");
            Thread.sleep(1000);
        } else {
            num = 200;
            System.out.println("tag b, set num over!");
        }

        System.out.println("tag " + tag + ", num = " + num);
    }

    public static void main(String[] args) {
        MultiThread m1 = new MultiThread();
        MultiThread m2 = new MultiThread();

        Thread t1 = new Thread(() -> {
            try{
                m1.printNum("a");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try{
                m2.printNum("b");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
    }
}

说明:定义了一个printNum方法,并给这个方法加了锁,这个方法内部是一个简单的if else判断而已,很简单。底下的main方法中,创建了两个MultiThread对象,分别为m1和m2,接下来又创建l了两个线程,分别是t1和t2,这两个线程的实现方式是直接使用匿名类创建对象的方式,可以直接使用接口,这里又使用了lamda表达式,所以看起来比较简略,实际上是创建的Runnable接口的对象,其中括号中的内容是覆写run方法的内容,可以看到两个不同的线程分别调用了不同对象的printNum方法,那么结果会是怎样的呢?

tag a, set num over!
tag b, set num over!
tag b, num = 200
tag a, num = 100

结果和我们预想的不对吗?当然不对,预想的应该是

tag a, set num over!
tag a, num = 100
tag b, set num over!
tag b, num = 200

这样才对,因为我们加了synchronized 关键字啊。
原因是这样的,因为我们这两个线程分别调用的是两个对象的printNum方法,虽然进行了加锁,但是他们并不是一个对象,也就是说,这个同步锁是加在对象上的,并没有加在类级别上,不同的对象调用这个方法,同步锁是没有用的。

那么如何让对象方法加锁执行呢,也就是让同步锁起作用呢,那就需要使用static关键字,代码修改为:

private static int num = 0;

    public static synchronized void printNum(String tag) throws InterruptedException {
        if (tag.equals("a")) {
            num = 100;
            System.out.println("tag a, set num over!");
            Thread.sleep(1000);
        } else {
            num = 200;
            System.out.println("tag b, set num over!");
        }

        System.out.println("tag " + tag + ", num = " + num);
    }

这样子再次执行查看效果:

tag a, set num over!
tag a, num = 100
tag b, set num over!
tag b, num = 200

结果就和我们预期的一样了,那么为什么加上static之后就可以了呢,因为我们加了static关键字之后,这个方法就变成了类方法,也就是说,这个方法是和类相关的,和某个对象是无关的了,所以就可以达到加锁的效果了。所以我们查看结果,就是a先执行,然后b才执行。

总结:

synchronized取得的锁都是对象锁,而不是把一段代码当做锁,所以示例代码中那个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),两个对象,线程获取的就是两个不同的锁,他们互不影响。
有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)

你可能感兴趣的:(java,多线程,互联网并发编程)