synchronized的初步使用
synchronized:内置锁,又被称为同步锁,隐式锁
一、synchronized的作用
当synchronized关键字修饰一个方法或者代码块时,能保证同一时刻最多只有一个线程执行该段代码
二、synchronized的使用
1. 在方法声明时使用
锁的是当前实例
/**
*
* 测试synchronized锁this和synchronized修饰方法 是否锁的同一个对象
* 如果是说明synchronized修饰方法锁的是当前类的实例
*/
public class SyncObjectDemo {
private int count;
private synchronized void incCount01() {
count++;
}
private void incCount02() {
synchronized (this) {
count++;
}
}
private static class IncCount01 extends Thread {
private SyncObjectDemo syncObjectDemo;
public IncCount01(SyncObjectDemo syncObjectDemo) {
this.syncObjectDemo = syncObjectDemo;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
syncObjectDemo.incCount01();
}
}
}
private static class IncCount02 extends Thread {
private SyncObjectDemo syncObjectDemo;
public IncCount02(SyncObjectDemo syncObjectDemo) {
this.syncObjectDemo = syncObjectDemo;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
syncObjectDemo.incCount02();
}
}
}
public static void main(String[] args) throws InterruptedException {
SyncObjectDemo syncObjectDemo = new SyncObjectDemo();
IncCount01 incCount01 = new IncCount01(syncObjectDemo);
IncCount02 incCount02 = new IncCount02(syncObjectDemo);
incCount01.start();
incCount02.start();
TimeUnit.MILLISECONDS.sleep(10);
System.out.println(syncObjectDemo.count);
}
}
代码运行完成后打印20000,说明两个线程锁的是同一个对象,即synchronized锁this对象和synchronized修饰方法是同样的效果,也就说明synchronized修饰方法锁的对象就是当前类的实例
2. 修饰在代码块上
锁的是括号里的对象
synchronized (this) {
count++;
}
3. 修饰静态方法(类锁)
锁的是类的clas对象
**
*
* 测试synchronized锁class对象和synchronized修饰静态方法 是否锁的同一个对象
* 如果是说明synchronized修饰静态方法锁的是当前类的class对象
*/
public class SyncClassDemo {
private static int count;
private static synchronized void incCount01() {
count++;
}
private void incCount02() {
synchronized (SyncClassDemo.class) {
count++;
}
}
private static class IncCount01 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
incCount01();
}
}
}
private static class IncCount02 extends Thread {
private SyncClassDemo syncClassDemo;
public IncCount02(SyncClassDemo syncClassDemo) {
this.syncClassDemo = syncClassDemo;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
syncClassDemo.incCount02();
}
}
}
public static void main(String[] args) throws InterruptedException {
SyncClassDemo syncClassDemo = new SyncClassDemo();
IncCount01 incCount01 = new IncCount01();
IncCount02 incCount02 = new IncCount02(syncClassDemo);
incCount01.start();
incCount02.start();
TimeUnit.MILLISECONDS.sleep(10);
System.out.println(count);
}
}
代码运行完成后打印20000,说明两个线程锁的是同一个对象,即synchronized锁class对象和synchronized修饰静态方法是同样的效果,也就说明synchronized修饰静态方法锁的对象就是当前类的class对象
三、隐式规则
- 当两个并发线程访问同一个对象object中的synchronized(obj)同步代码块时,一个时间内只能有一个线程得到执行,另外一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
- 当一个线程访问object的一个同步代码块时,另外一个线程可以访问object中的非同步代码块
- 当一个线程访问object的一个同步代码块时,其他线程对object中的所有其他同步代码块的访问将被阻塞
四、选择合适的锁
synchronized不同的写法程序响应的快慢和对CPU等资源高并发的利用程度也不一样,性能和执行效率得优劣程度如下
同步方法体 < synchronized(this) < synchronizd(小obj)
- 同步方法体即使获得了锁,进入方法体还得分配资源需要一定的时间
- 加锁和释放锁都需要加锁的对象的资源,因此锁的对象越小越好,开发中常创建一个小对象作为加锁对象
例如:
private byte[] lock = new byte[1];
public void testSync(){
synchronized(lock){
// TODO
}
}