**
浅析synchronized类锁和对象锁
**
近日重新复习了下java多线程的基本知识,在此写下了作为笔记。若有失实指出还望大家批评指正。
若有朋友转载,请注明原址,谢谢!
老生常谈
java多线程的好处:
充分利用CPU资源,加快程序处理效率,使程序模块化、异步化
多线程所带来的问题:
1.线程的共享资源容易发生冲突
2.可能会发生死锁。
3.启动太多线程会导致资源不足
本文主要就synchronized关键字的使用做简单介绍
synchronized关键字
synchronized关键字和lock是java最常用的锁机制的实现方式。
对比来讲synchronized代码相对简洁,但是效率较lock来说低一些,且没有lock灵活。其逻辑由虚拟机底层实现,使用起来更方便。
lock会在后续博客中介绍。
synchronized的使用情况主要有如下两种:
1.java对象锁:
//对象锁
public synchronized void instence() throws InterruptedException{
System.out.println("Test instence() is begin...");
Thread.sleep(10000);
System.out.println("Test instence() is end...");
}
2.java类锁:
//类锁
public static synchronized void classLock() throws InterruptedException{
System.out.println("Test classLock() is begin...");
Thread.sleep(10000);
System.out.println("Test classLock() is end...");
}
在用法上来说,类锁只比对象锁多了一个static关键字,但是两者锁住的东西却不相同。
先说对象锁,顾名思义,synchronized虽然写在方法上,但是却锁住的是整个对象。也就是说,当一个类中两个方法(A和B)均使用对象锁,在此对象实例化后A方法获取锁调用过程中,其他线程在B方法上是阻塞的。
具体示例如下:
//test类
class Test{
//对象锁
public synchronized void instence() throws InterruptedException{
System.out.println("Test instence() is begin...");
Thread.sleep(10000);
System.out.println("Test instence() is end...");
}
//对象锁2
public synchronized void instence2() throws InterruptedException{
System.out.println("Test instence2() is begin...");
Thread.sleep(10000);
System.out.println("Test instence2() is end...");
}
//类锁
public static synchronized void classLock() throws InterruptedException{
System.out.println("Test classLock() is begin...");
Thread.sleep(10000);
System.out.println("Test classLock() is end...");
}
}
//两个线程1和2,其中1调用test的instence()方法,2调用instence2()方法
class TestThread implements Runnable{
Test test;
public TestThread(Test test) {
this.test = test;
}
@Override
public void run() {
try {
test.instence();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class TestThread2 implements Runnable{
Test test;
public TestThread2(Test test) {
this.test = test;
}
@Override
public void run() {
try {
test.instence2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//主线程
public class SyncLockKinds {
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
new Thread(new TestThread(t)).start();
new Thread(new TestThread2(t)).start();
t.instence();
}
}
运行结果:
Test instence() is begin...
Test instence() is end...
Test instence2() is begin...
Test instence2() is end...
Test instence() is begin...
Test instence() is end...
从结果可以看出每个方法均在前一个方法执行完成后才开始执行。但是instence()和instence2()为不同的两个方法。所以证明synchronized锁住的是对象本身。
此处需注意,得保证多线程所锁的是同一对象,以下代码为错误示范:
public class SyncLockKinds {
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
Test t2 = new Test();
new Thread(new TestThread(t)).start();
new Thread(new TestThread2(t2)).start();
// t.instence();
}
}
运行结果如下:
Test instence() is begin...
Test instence2() is begin...
Test instence() is end...
Test instence2() is end...
再说类锁:
虚拟机保证每个类只有一个class对象,所以每个类只有一个类锁。
以上代码的Test类不变,线程修改如下:
class TestThread implements Runnable{
Test test;
public TestThread(Test test) {
this.test = test;
}
@Override
public void run() {
try {
test.instence();
// Test.classLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class TestThread2 implements Runnable{
Test test;
public TestThread2(Test test) {
this.test = test;
}
@Override
public void run() {
try {
// test.instence2();
Test.classLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//主方法
public class SyncLockKinds {
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
new Thread(new TestThread(t)).start();
new Thread(new TestThread2(t)).start();
// t.instence();
}
}
运行结果:
Test instence() is begin...
Test classLock() is begin...
Test instence() is end...
Test classLock() is end...
由此可见,类锁和对象锁锁的并非同一区域
同步代码块
理解对象锁和类锁后 对同步代码块的理解就会简单很多
先说用法:
public class SyncLockKinds {
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
synchronized (t) {
t.instence2();
...
}
synchronized (test.getClass()) {
test.instence2();
...
}
}
}
同步代码块相对来说更加灵活,若执行某同步方法,用完此方法后即释放了锁,但若想再执行另一个此对象带锁的同步方法需要重新获取。(此时虚拟机无法保证还是上一个归还锁的人继续获得锁)
而同步块则是当块内代码执行完成才释放锁,执行过程中无需归还锁。
关于synchronized这里就说这些,今后我会持续更新…希望大家多多批评指正,共同进步。