synchronized对象锁

/ 多线程 / 没有评论 / 297浏览

上一篇我们介绍了实例变量在多线程中会有线程安全问题它的解决办法就是添加synchronized关键字。这篇我们介绍synchronized关键字锁的概念,在介绍它之前,我们在分析一下上一篇中实例变量的例子。

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

private int role = 0;

public synchronized void login(String username) {
try {
if ("admin".equals(username)) {
role = 1;
System.out.println("管理用户登录");
Thread.sleep(1000);
} else {
role = 2;
System.out.println("普通用户登录");
}
System.out.println(String.format("uername: %s\trole: %s", username, role));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 管理用户请求
*
* @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.login("admin");
}
}
/**
* 普通用户请求
*
* @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.login("user");
}
}
/**
* 测试类
*
* @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 admin = new RequestAdmin(userinfo);
RequestUser user = new RequestUser(userinfo);
admin.start();
user.start();
}
}
管理用户登录
uername: admin	role: 1
普通用户登录
uername: user	role: 2
普通用户登录
uername: user	role: 2
管理用户登录
uername: admin	role: 1

我们看在多次测试结果中显示,如果在方法中添加了synchronized关键字的确解决了线程安全问题,但线程的执行变成同步的了。因为如果线程一先进入含有synchronized关键字的方法时,首先要获取锁,这个锁其实就是当前对象,所以锁也叫对象锁。如果能够获取到锁时那么线程就进入这个方法继续执行。如果没有获取到锁时,那当前线程就不断的尝试获取,直到获取锁成功为止。当线程获取到锁进入synchronized方法执行时,这个锁一直不会释放,所以其它线程也就获取不到这个锁,所以它也就进入不到synchronized方法。从而保证了线程的安全运行。所以输出信息的显示就会出现同步的情况。那么我们继续下面下的例子。

/**
* 测试类
*
* @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 userinfo1 = new Userinfo();
Userinfo userinfo2 = new Userinfo();
RequestAdmin admin = new RequestAdmin(userinfo1);
RequestUser user = new RequestUser(userinfo2);
admin.start();
user.start();
}
}
管理用户登录
普通用户登录
uername: user	role: 2
uername: admin	role: 1

我们只修改了测试类的代码,其它的代码不变。我们发现输出结果显示还是线程安全的,但它们不是同步输出的了而是异步输出了,按照我个上面的分析它应该是同步输出的,因为当一个线程执行时,另一个线程并不能获取到锁,看出输出结果,貌似一个线程在执行时其它线程也获取到了锁。这又是为什么呢?这是因为synchronized关键字取得的锁都是对象锁,而不是方法锁,前面已经介绍了,哪个线程获取到了锁,那么其它线程只能等待,但这里有一个前提就是多个线程必须访问的是同一个对象。如果多个线程访问的是多个对象,那JVM就会创建多个锁,所以在线程一获取当前对象锁时,其它线程还是可以获取到锁的只是这两个锁不是同个锁而已,所以它们依然可以异步执行。