对象锁
public class MultiThred {
int tag =0;
synchronized void print_num(String num) {
try {
if("a".equals(num)){
tag = 100;
System.out.println(" num is "+tag );
Thread.sleep(2000);
}else{
tag =200;
System.out.println(" num is "+tag );
}
System.out.println("thread "+num+" is over");
} catch (InterruptedException e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
final MultiThred t1 = new MultiThred();
final MultiThred t2 = new MultiThred();
Thread mt1 = new Thread(new Runnable() {
@Override
public void run() {
try {
t1.print_num("a");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread mt2 = new Thread(new Runnable() {
@Override
public void run() {
try {
t2.print_num("b");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
mt1.start();
mt2.start();
}
}
运行程序输出结果为
num is 200
num is 100
thread b is over
thread a is over
结果表明thread a 和thread b 是独立运行的,并没有产生a线程阻塞b线程的效果,原因是t1和t2是连两个对象,而sychronized是对象锁,只能对对象内的值进行加锁,所以此时锁对两个对象的操作无效
类锁
代码
public class MultiThred {
static int tag =0;
static synchronized void print_num(String num) {
try {
if("a".equals(num)){
tag = 100;
System.out.println(" num is "+tag );
Thread.sleep(2000);
}else{
tag =200;
System.out.println(" num is "+tag );
}
System.out.println("thread "+num+" is over");
} catch (InterruptedException e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
final MultiThred t1 = new MultiThred();
final MultiThred t2 = new MultiThred();
Thread mt1 = new Thread(new Runnable() {
@Override
public void run() {
try {
t1.print_num("a");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread mt2 = new Thread(new Runnable() {
@Override
public void run() {
try {
t2.print_num("b");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
mt1.start();
mt2.start();
}
}
此时结果为
num is 100
thread a is over
num is 200
thread b is over
Thread b直到Thread a 执行完才会执行,
为什么static修饰的sychronized方法是类锁
某博客是这样写的
一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。
对于对象来说,相关联的监视器保护对象的实例变量。
对于类来说,监视器保护类的类变量。
(如果一个对象没有实例变量,或者一个类没有变量,相关联的监视器就什么也不监视。)
为了实现监视器的排他性监视能力,java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。
但是如果线程获取了锁,那么在它释放这个锁之前,就没有其他线程可以获取同样数据的锁了。(锁住一个对象就是获取对象相关联的监视器)
类锁实际上用对象锁来实现。当虚拟机装载一个class文件的时候,它就会创建一个java.lang.Class类的实例。当锁住一个对象的时候,实际上锁住的是那个类的Class对象。
一个线程可以多次对同一个对象上锁。对于每一个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减 1,当计数器值为0时,锁就被完全释放了。
java编程人员不需要自己动手加锁,对象锁是java虚拟机内部使用的。
在java程序中,只需要使用synchronized块或者synchronized方法就可以标志一个监视区域。当每次进入一个监视区域时,java 虚拟机都会自动锁上对象或者类。synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问该实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于 this.synchronized
参考自
Java对象锁和类锁全面解析(多线程synchronized关键字)
博客园首页新随笔联系管理订阅
synchronized与static synchronized 的区别