synchronized静态同步方法与非静态同步方法锁的验证

我们知道非静态synchronized同步方法的锁是当前对象,那么静态synchronized同步方法的锁到底 […]

我们知道非静态synchronized同步方法的锁是当前对象,那么静态synchronized同步方法的锁到底是什么呢?在一上篇我们没有介绍这个锁到底是什么,但我们知道这个锁一定不是当前对象,否则静态synchronized同步方法和非静态同步方法在多线程执行时就应该是同步执行的,但执行结果确是异步的。(在上一篇有这样的事例)我们先不谈这个锁到底是什么,我们先通过下面的例子来验证一下非静态synchronized同步方法的锁是不是当前对象。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

    public synchronized void adminLogin() {
        System.out.println(String.format("start: %s	thread: %s", "admin", Thread.currentThread().getName()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("end: %s	thread: %s", "admin", Thread.currentThread().getName()));
    }

    public void userLogin() {
        synchronized (this) {
            System.out.println(String.format("start: %s	thread: %s", "user", Thread.currentThread().getName()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("end: %s	thread: %s", "user", Thread.currentThread().getName()));
        }
    }

}
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Userinfo userinfo;

    public RequestAdmin(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.adminLogin();
    }
}
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {

    private Userinfo userinfo;

    public RequestUser(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.userLogin();
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) {
        Userinfo userinfo = new Userinfo();
        RequestAdmin requestAdmin = new RequestAdmin(userinfo);
        RequestUser requestUser = new RequestUser(userinfo);
        requestAdmin.start();
        requestUser.start();
    }
}
start: admin	thread: Thread-0
end: admin	thread: Thread-0
start: user	thread: Thread-1
end: user	thread: Thread-1

我们都加了synchronized同步关键字,但确有所区别。一个是用的synchronized同步方法,一个用的是synchronized同步代码块。我们知道synchronized同步代码块是要传一个参数的,这个参数就是synchronized同步代码块的锁。我们上述代码中传的是this也就是指当前对象。也就是当前对象是synchronized同步代码块的锁。如果程序执行是同步的那就说明synchronized同步方法的锁也是当前对象。如果程序执行是异步的那就说明synchronized同步方法的锁不是当前对象。如果我们将synchronized同步代码块的锁改成其它的对象那程序就会是异步执行的。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

    public synchronized void adminLogin() {
        System.out.println(String.format("start: %s	thread: %s", "admin", Thread.currentThread().getName()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("end: %s	thread: %s", "admin", Thread.currentThread().getName()));
    }

    public void userLogin() {
        synchronized (new Object()) {
            System.out.println(String.format("start: %s	thread: %s", "user", Thread.currentThread().getName()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("end: %s	thread: %s", "user", Thread.currentThread().getName()));
        }
    }

}
start: user	thread: Thread-1
start: admin	thread: Thread-0
end: user	thread: Thread-1
end: admin	thread: Thread-0

综上所述,非静态synchronized方法的锁是当前对象。接下来我们用同样的方式来验证静态synchronized同步方法的锁不是当前对象。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

    public synchronized static void adminLogin() {
        System.out.println(String.format("start: %s	thread: %s", "admin", Thread.currentThread().getName()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("end: %s	thread: %s", "admin", Thread.currentThread().getName()));
    }

    public static void userLogin(Object o) {
        synchronized (o) {
            System.out.println(String.format("start: %s	thread: %s", "user", Thread.currentThread().getName()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("end: %s	thread: %s", "user", Thread.currentThread().getName()));
        }
    }

}
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Userinfo userinfo;

    public RequestAdmin(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.adminLogin();
    }
}
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {

    private Userinfo userinfo;

    public RequestUser(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.userLogin(userinfo);
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) {
        Userinfo userinfo = new Userinfo();
        RequestAdmin requestAdmin = new RequestAdmin(userinfo);
        RequestUser requestUser = new RequestUser(userinfo);
        requestAdmin.start();
        requestUser.start();
    }
}
start: user	thread: Thread-1
start: admin	thread: Thread-0
end: user	thread: Thread-1
end: admin	thread: Thread-0

我们把代码做了一些修改我们把锁当成一个参数传入到了synchronized同步代码块中,虽然这个锁传递成功了,但程序执行还是异步的说明静态synchronized同步方法的锁不是当前对象。那静态synchronized同步方法锁到底是什么呢?答案就是当前对象的Class是静态synchronized同步方法的锁。我们看先下面的事例然后在具体说明它的原因。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

    public synchronized static void adminLogin() {
        System.out.println(String.format("start: %s	thread: %s", "admin", Thread.currentThread().getName()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("end: %s	thread: %s", "admin", Thread.currentThread().getName()));
    }

    public static void userLogin(Object o) {
        synchronized (o.getClass()) {
            System.out.println(String.format("start: %s	thread: %s", "user", Thread.currentThread().getName()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("end: %s	thread: %s", "user", Thread.currentThread().getName()));
        }
    }

}
start: admin	thread: Thread-0
end: admin	thread: Thread-0
start: user	thread: Thread-1
end: user	thread: Thread-1

我们只做了一处修改就是我们不直接把传入的对象当做synchronized同步代码块的锁,而是获取传入对象的当前class。通过输出信息我们发现线程现在是同步执行的了,这就验证了我们上述所说的结论。静态synchronized同步方法的锁是当前对象的class。那为什么是class而不是当前对象呢。这是因为我们知道在Java中如果方法是静态方法,那么这个方法可以在没有实例化对象的时候就可直接调用,没有实例化也就是没有对象,连对象都没有怎么可以用当前对象当做静态同步方法的锁呢。但class不一样的,如果JVM成功加载了这个类就会自动创建class,不用考虑这个对象是否实例化。所以在Java中静态synchronized方法的锁是当前对象的class。事实上如果你直接在静态的synchronized同步代码块中用this当锁的话,编译都是通不过的。因为静态方法中根本就没有this对象。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧