Java并发编程之同步关键字synchronized

昨天部门新人培训,讲到synchronized关键字的问题,发现对于synchronized的使用有些不太懂,于是今天总结一下:

很久之前我在Java编程思想之并发编程这篇文章中写过,什么时候该使用同步?运用Brian同步规则:如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个写过的变量,那么你必须使用同步,并且读写线程必须使用相同的监视器锁同步。

同步分为两种,一种是多个线程共享同一个资源,该资源同一时刻只能让一个线程访问,对共享资源的互斥访问,利用synchronized关键字或者Lock等实现。另一种是多个线程协作解决某一个问题,某个线程必须在另一个线程之前或者之后完成,线程之间的顺序问题,利用wait()和notify()实现。

synchronized的作用对象

  • 总体来说synchronized关键字可以作用于变量、对象、函数和类名上面;函数又包括静态函数和非静态函数两种。
  • 无论synchronized关键字加载方法上还是对象上,它取得的锁都是对象,而不是一段代码或函数当做锁。
  • 每个对象只有一个锁与之相关联。

synchronized关键字的作用域

  • 某个对象实例内,synchronized get5(){},synchronized (this) {}这两种方式可以防止多个线程访问同一对象的synchronized 方法或者synchronized (this) {}所包含的代码块。
  • 某个对象内,如下代码所示:可以防止多个线程访问同一对象。
private Object staticLock = new Object();

    public void get1() {
        synchronized (staticLock) {
            System.out.println("void get1() synchronized (staticLock)");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("释放资源" + "staickLock");
    }
  • 以上两种是在对象的范围内,也就是说不同对象是互不干扰的。
  • 某个类的范围内,如下面两种方式:他们锁的对象的这个类的class文件。
public void get2(){
        synchronized (SynchronizeEntity.class) {
            System.out.println("void get2() synchronized (SynchronizeEntity.class)");

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("释放资源" + "SynchronizeEntity.class");
    }

    public synchronized static void get3(){
        System.out.println("synchronized static void get3()");
    }
  • 只要锁的对象不一样,在不同线程就可以同时访问。
package com.xqq.entity.test;

public class SynchronizeEntity {

    private Object staticLock = new Object();

    public void get1() {
        synchronized (staticLock) {
            System.out.println("void get1() synchronized (staticLock)");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("释放资源" + "staickLock");
    }

    public void get2(){
        synchronized (SynchronizeEntity.class) {
            System.out.println("void get2() synchronized (SynchronizeEntity.class)");
            // 睡眠 占用所资源不释放
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("释放资源" + "SynchronizeEntity.class");
    }

    public synchronized static void get3(){
        System.out.println("synchronized static void get3()");
    }

    public void get4() {
        synchronized (this) {
            System.out.println("void get4()  synchronized (this)");
        }
        System.out.println("释放资源" + "this");
    }

    public synchronized void get5() {
        System.out.println("synchronized void get5()");
    }
}


package com.xqq.entity.test;
public class Test {

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {

            public void run() {
                // 访问synchronized (SynchronizeEntity.class) {}修饰的方法,属于类级别
                SynchronizeEntity test1 = new SynchronizeEntity();
                test1.get2();
            }
        }).start();

        Thread.sleep(1000);

        new Thread(new Runnable() {
            // 访问 synchronized void get5() {}方法,属于对象级别
            public void run() {
                SynchronizeEntity test1 = new SynchronizeEntity();
                test1.get5();
            }
        }).start();
    }
}

运行结果:
void get2() synchronized (SynchronizeEntity.class)
synchronized void get5()
释放资源SynchronizeEntity.class

由结果可以看出:访问对象级别的同步方法并不需要等待类级别的方法释放 锁资源。

你可能感兴趣的:(Java基础)