一、对象锁
对象锁,顾名思义是锁住对象,不同实例的锁互不影响。
对象锁有两种加锁的方式,主要却在于Synchronized作用的地方的不同
1.作用在实例方法上
public synchronized void method(){}
2.作用在代码块上
public void method(){
synchronized(this){
//这里是需要同步的部分
}
}
持有相同对象锁的地方会出现互斥:
public synchronized void method1(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了对象锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void method2(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了对象锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest test1=new SynchronizedTest();
SynchronizedTest test2=new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
test1.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test1.method2();
}
}).start();
}
执行结果:
Thread-0持有了对象锁
Thread-0持有了对象锁
Thread-0持有了对象锁
Thread-0持有了对象锁
Thread-0持有了对象锁
Thread-0持有了对象锁
Thread-0持有了对象锁
这里的运行结果实际上陷入了死循环。因为我设置了while(ture),可以看到,Thread-0持有了当前对象的锁之后,就会排斥持有相同对象锁的线程。
synchronized修饰在实例方法上,代表着这里锁的是当前对象this.
那么对于不同的对象,将不会产生相互影响:
public static void main(String[] args) {
SynchronizedTest test1=new SynchronizedTest();
SynchronizedTest test2=new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
test1.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test2.method2();//调用不同对象的方法
}
}).start();
}
运行结果:
Thread-0持有了对象锁
Thread-1持有了对象锁
Thread-0持有了对象锁
Thread-1持有了对象锁
Thread-0持有了对象锁
Thread-1持有了对象锁
可以看到持有不同对象锁的线程互不影响。
synchronized(object){}
的效果和在实例方法上加锁一样,不同的是可以在()里添加不同的对象,例如:
synchronized(object1){}
synchronized(object2){}
当括号里的对象是一样时,表示持有的是同一对象锁,反之,就不是同一对象锁,那么线程调用时互不干扰。
当synchronized(object){}
()中的对象与实例方法上锁的是同一对象,那么将会互斥。例如:
public synchronized void method(){}
public void method(){
synchronized(this){
//这里是需要同步的部分
}
这里,都代表锁的是当前类的对象,所持有的锁是同一把。
二、类锁
不管多少对象都共用同一把锁,同步执行,一个线程执行结束、其他的才能够调用同步的部分
也是有两种不同的加锁方式。不同的类锁互不影响
1.用synchronized修饰静态方法
public synchronized static void method()
2.作用在代码块上
public void method(){
synchronized(object.class){
}
}
当持有类锁时,所有实例调用这个方法上都会互相排斥。
public synchronized static void staticMethod1(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了类锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized static void staticMethod2(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了类锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest test1=new SynchronizedTest();
SynchronizedTest test2=new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
test1.staticMethod1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test2.staticMethod2();
}
}).start();
}
运行结果:
Thread-0持有了类锁
Thread-0持有了类锁
Thread-0持有了类锁
Thread-0持有了类锁
Thread-0持有了类锁
Thread-0持有了类锁
可以看到,虽说调用的是不同对象的同步方法,但还是产生了互斥。
对象锁和类锁会互斥吗?
//对象锁
public synchronized void method1(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了对象锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//类锁
public synchronized static void staticMethod1(){
while (true){
System.out.println(Thread.currentThread().getName()+"持有了类锁");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
new Thread(new Runnable() {
@Override
public void run() {
test1.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test1.staticMethod1();
}
}).start();
}
运行结果:
Thread-0持有了对象锁
Thread-1持有了类锁
Thread-0持有了对象锁
Thread-1持有了类锁
Thread-0持有了对象锁
Thread-1持有了类锁
可以看到对象锁和类锁互不影响。