Java中synchronized 修饰在 static方法和 非static方法的区别

Java中synchronized是用来表示同步的,synchronized可以用来修饰一个方法(static方法和非static方法),也可以用来修饰一段代码块;

修饰实例方法:

public synchronized void x() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("x <--------------");
        }
    }

    public static synchronized void staticX() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("staticX <--------------");
        }
    }
’static’的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,就是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。而‘非static’方法获取到的锁,就是当前调用这个方法的对象的锁了。所以,他们之间不会产生互斥。
main方法:

public static void main(String[] args) {
        final Test test1 = new Test();
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    test1.x();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "a");

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                try {
                    Test.staticX();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }, "b");

        thread.start();
        thread1.start();
    }

运行结果:

x <--------------
staticX <--------------
x <--------------
staticX <--------------
staticX <--------------
x <--------------
x <--------------
staticX <--------------
staticX <--------------
x <--------------

那当我们想让所有这个类下面的对象都同步的时候,也就是让所有这个类下面的对象共用同一把锁的时候,我们如何办呢?

代码如下:

public class Test2 {
    //创建一个对象
    final static Test2 ce = new Test2();
    public static void staticX() throws Exception {
        /**此处的synchronized 和下面的 x()中的synchronized它们调用的都是同一对象‘ce’,
         * 那么此时Test2中的两个方法(所有的方法),公用的都是同一把锁
         * 此处解释的可能不太正确,反正大致就是这个意思
         */
        synchronized (ce) {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("staticX.......................");
            }
        }
    }

    public void x() throws InterruptedException {
        synchronized (ce) {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("x.......................");
            }
        }
    }

    public static void main(String[] args) {
        final Test2 test1 = new Test2();
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    test1.x();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "a");

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                try {
                    Test2.staticX();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "b");

        thread1.start();
        thread.start();
    }
}

运行结果:

staticX.......................
staticX.......................
staticX.......................
staticX.......................
staticX.......................
x.......................
x.......................
x.......................
x.......................
x.......................


一个关于多线程的实验,摘录自http://blog.csdn.net/hey_a_hao/article/details/10155503

/**
 * Created by LUOFENG on 2017/3/21.
 */
public class JoinThread extends Thread {

    public static int i = 0;

    public synchronized void inc() {
        i++;
    }

    @Override
    public void run() {
        for (int x = 0; x < 10; x++) {
            inc();
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] t = new Thread[10];
        for (int i = 0; i < t.length; i++) {
            t[i] = new JoinThread();
        }
        for (int i = 0; i < t.length; i++) {
            t[i].start();
        }
        for (int i = 0; i < t.length; i++) {
            t[i].join();
        }
        System.out.println(JoinThread.i);
    }
}

执行完发现,i并没有如想像中的输出1000,即使i添加volatile进行修饰,也不会输出1000,值是随机变化的。


将inc()方法添加static修饰,结果无问题,准确无误的输出1000。


另外一种改法,将代码改成:

[java]  view plain  copy
  1. Thread[] t = new Thread[100];  
  2. for (int i = 0; i < t.length; i++) {  
  3.     t[i] = new JoinThread();  
  4. }  
修改成:

[java]  view plain  copy
  1. JoinThread jt = new JoinThread();  
  2. Thread[] t = new Thread[100];  
  3. for (int i = 0; i < t.length; i++) {  
  4.     t[i] = new Thread(jt);  
  5. }  
结果无问题,准确无误的输出1000


这里主要涉及到类对象(static方法),对象方法(非static方法)

我们知道,当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例);

当synchronized修饰一个非static方法时,多线程下,获取的是对象锁(即类的实例对象)

所以,当synchronized修饰一个static方法时,创建线程不管是new JoinThread()还是new Thread(new JoinThread()),在run方法中执行inc()方法都是同步的;

相反,当synchronized修饰一个非static方法时,如果用new JoinThread()还是new Thread(new JoinThread())方式创建线程,就无法保证同步操作,因为这时

inc()是属于对象方法,每个线程都执有一个独立的对象实例new JoinThread(),所以多线程下执行inc()方法并不会产生互斥,也不会有同步操作。


另外如果考虑到变更的原子操作,可使用atomic包下面的包装对象,这些对象都是对volatile修饰变量的一种延伸,可保证变量的原子操作而不用去同步方法或

代码块是否同步。



 
  



你可能感兴趣的:(学习记录)