zoukankan      html  css  js  c++  java
  • Java多线程系列 基础篇05 synchronized关键字

    1. synchronized原理

    在java中,每一个对象有且仅有一个同步锁,所以同步锁是依赖于对象而存在。当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。

    2. synchronized基本规则

    我们将synchronized的基本规则总结为下面3条,并通过实例对它们进行说明。
    ①: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
    ②: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
    ③: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

    代码示例:
    ①当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

    class Count {
    
        // 含有synchronized同步块的方法
        public void synMethod() {
            synchronized(this) {
                try {  
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(100); // 休眠100ms
                        System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);  
                    }
                } catch (InterruptedException ie) {  
                }
            }  
        }
    
        // 也包含synchronized同步块的方法
        public void nonSynMethod() {
            synchronized(this) {
                try {  
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);  
                    }
                } catch (InterruptedException ie) {  
                }
            }
        }
    }
    
    public class Demo3 {
    
        public static void main(String[] args) {  
            final Count count = new Count();
            // 新建t1, t1会调用“count对象”的synMethod()方法
            Thread t1 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.synMethod();
                        }
                    }, "t1");
    
            // 新建t2, t2会调用“count对象”的nonSynMethod()方法
            Thread t2 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.nonSynMethod();
                        }
                    }, "t2");  
    
    
            t1.start();  // 启动t1
            t2.start();  // 启动t2
        } 
    }
    

    运行结果:

    t1 loop 0
    t1 loop 1
    t1 loop 2
    t1 loop 3
    t1 loop 4
    t2 loop 0
    t2 loop 1
    t2 loop 2
    t2 loop 3
    t2 loop 4 
    

    结果说明:
    run()方法中存在“synchronized(this)代码块”,而且t1和t2都是基于"demo这个Runnable对象"创建的线程。这就意味着,我们可以将synchronized(this)中的this看作是“demo这个Runnable对象”;因此,线程t1和t2共享“demo对象的同步锁”。所以,当一个线程运行的时候,另外一个线程必须等待“运行线程”释放“demo的同步锁”之后才能运行。

    ②: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。

    class Count {
    
        // 含有synchronized同步块的方法
        public void synMethod() {
            synchronized(this) {
                try {  
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(100); // 休眠100ms
                        System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);  
                    }
                } catch (InterruptedException ie) {  
                }
            }  
        }
    
        // 非同步的方法
        public void nonSynMethod() {
            try {  
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);  
                }
            } catch (InterruptedException ie) {  
            }
        }
    }
    
    public class Demo2 {
    
        public static void main(String[] args) {  
            final Count count = new Count();
            // 新建t1, t1会调用“count对象”的synMethod()方法
            Thread t1 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.synMethod();
                        }
                    }, "t1");
    
            // 新建t2, t2会调用“count对象”的nonSynMethod()方法
            Thread t2 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.nonSynMethod();
                        }
                    }, "t2");  
    
    
            t1.start();  // 启动t1
            t2.start();  // 启动t2
        } 
    }
    

    运行结果:

    t1 synMethod loop 0
    t2 nonSynMethod loop 0
    t1 synMethod loop 1
    t2 nonSynMethod loop 1
    t1 synMethod loop 2
    t2 nonSynMethod loop 2
    t1 synMethod loop 3
    t2 nonSynMethod loop 3
    t1 synMethod loop 4
    t2 nonSynMethod loop 4
    

    结果说明:
    主线程中新建了两个子线程t1和t2。t1会调用count对象的synMethod()方法,该方法内含有同步块;而t2则会调用count对象的nonSynMethod()方法,该方法不是同步方法。t1运行时,虽然调用synchronized(this)获取“count的同步锁”;但是并没有造成t2的阻塞,因为t2没有用到“count”同步锁。

    ③: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

    class Count {
    
        // 含有synchronized同步块的方法
        public void synMethod() {
            synchronized(this) {
                try {  
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(100); // 休眠100ms
                        System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);  
                    }
                } catch (InterruptedException ie) {  
                }
            }  
        }
    
        // 也包含synchronized同步块的方法
        public void nonSynMethod() {
            synchronized(this) {
                try {  
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);  
                    }
                } catch (InterruptedException ie) {  
                }
            }
        }
    }
    
    public class Demo3 {
    
        public static void main(String[] args) {  
            final Count count = new Count();
            // 新建t1, t1会调用“count对象”的synMethod()方法
            Thread t1 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.synMethod();
                        }
                    }, "t1");
    
            // 新建t2, t2会调用“count对象”的nonSynMethod()方法
            Thread t2 = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            count.nonSynMethod();
                        }
                    }, "t2");  
    
    
            t1.start();  // 启动t1
            t2.start();  // 启动t2
        } 
    }
    

    运行结果:

    t1 synMethod loop 0
    t1 synMethod loop 1
    t1 synMethod loop 2
    t1 synMethod loop 3
    t1 synMethod loop 4
    t2 nonSynMethod loop 0
    t2 nonSynMethod loop 1
    t2 nonSynMethod loop 2
    t2 nonSynMethod loop 3
    t2 nonSynMethod loop 4
    

    结果说明:
    主线程中新建了两个子线程t1和t2。t1和t2运行时都调用synchronized(this),这个this是Count对象(count),而t1和t2共用count。因此,在t1运行时,t2会被阻塞,等待t1运行释放“count对象的同步锁”,t2才能运行。

    3. synchronized方法 和 synchronized代码块

  • 相关阅读:
    win7下的vxworks总结
    ubuntu 无法获得锁 /var/lib/dpkg/lock
    项目中用到了的一些批处理文件
    win7下安装 WINDRIVER.TORNADO.V2.2.FOR.ARM
    使用opencv统计视频库的总时长
    January 05th, 2018 Week 01st Friday
    January 04th, 2018 Week 01st Thursday
    January 03rd, 2018 Week 01st Wednesday
    January 02nd, 2018 Week 01st Tuesday
    January 01st, 2018 Week 01st Monday
  • 原文地址:https://www.cnblogs.com/lizhouwei/p/9073868.html
Copyright © 2011-2022 走看看