java线程安全篇之synchronized 多个线程多个锁(二)

科技快讯

      北京时间15日晚据CNBC报道,微软创始人比尔-盖茨表示,技术可能将加剧贫富差距。因为技术进步所带来的好处,可能不是每个人都能享受到。
      他在沙特利雅得举办的米斯克全球论坛(Misk Global Forum)表示,“如果我们不小心,技术会加剧富人和穷人之间的差距。因为如果技术只在费用昂贵的学校教授,它就不能惠及每一个人。”
      这位亿万富翁还谈到了人工智能(AI)的担忧,他表示,类似人工智能(AI)这样的科技进步所带来的好处超过了任何潜在的陷阱,“我们处在一个短缺的世界,而这些进步将帮助我们解决所有首要问题。”
      在几天前,著名物理学家史蒂芬-霍金-对AI的出现发出警告,称这可能是“人类文明史上最糟糕的事件”,除非社会找到控制其发展的方法。

多个线程多个锁

快速理解

      多个线程,每个线程都可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容。

案例

package cn.hfbin.base.sync002;
/**
 * @author cn.hfbin
 *
 */
public class MultiThread {

    private int num = -1;

    /** static */
    public synchronized void printNum(String tag){
        try {

            if(tag.equals("a")){
                num = 1;
                System.out.println("Thread m1");
                Thread.sleep(1000);
            } else {
                num = 2;
                System.out.println("Thread m2");
            }

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

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //注意观察run方法输出顺序
    public static void main(String[] args) {

        //两个不同的对象
        final MultiThread m1 = new MultiThread();
        final MultiThread m2 = new MultiThread();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                m1.printNum("a");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override 
            public void run() {
                m2.printNum("b");
            }
        });     

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

    }
}

打印结果:

Thread m1
Thread m2
Thread b, num = 2
Thread a, num = 1

按照我们正常的思维打印的结果应该是

Thread m1
Thread a, num = 1
Thread m2
Thread b, num = 2

如此说明 关键字synchronized取得的锁都是对象锁,他们互不影响,m1和m2的信息都保存在自己的线程栈中,对其他线程不可见,t1和t2并发执行。

如果在printNum方法上加上static关键字,那它的打印结果又将会是怎样呢。如下案例:

public class MultiThread {

    private static int num = -1;

    /**
     * static
     */
    public static synchronized void printNum(String tag) {
        try {

            if (tag.equals("a")) {
                num = 1;
                System.out.println("Thread m1");
                Thread.sleep(1000);
            } else {
                num = 2;
                System.out.println("Thread m2");
            }

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

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //注意观察run方法输出顺序
    public static void main(String[] args) {

        //俩个不同的对象
        final MultiThread m1 = new MultiThread();
        final MultiThread m2 = new MultiThread();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                m1.printNum("a");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                m2.printNum("b");
            }
        });

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

    }
}

打印的结果

Thread m1
Thread a, num = 1
Thread m2
Thread b, num = 2

加上了static之后打印结果才是我们预料之中的结果,在printNum方法上加上static关键字,表示锁定class类。不管声明多少个MultiThread引用,printNum方法跟随类存放在堆上,线程间会共享资源,输出结果会等m1信息输出结束之后才会开始输出m2信息

案例总结

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

源代码:https://github.com/hfbin/Thread_Socket/tree/master/Thread/sync002

你可能感兴趣的:(java,线程,线程安全)