指标:理解Synchronized的含义,明确Synchronized关键字修饰普通方法、静态方法和代码块时锁对象的差异
1、含义:Synchronized是Java中解决并发问题的一种最常见的方法,也是最简单的一种方法。用于处理多线程中访问相同资源造成冲突的一种同步锁,实现代码的中的同步机制。
2、作用:主要有三个作用
①确保线程互斥的访问同步代码块
②保证共享变量的修改能够及时可见
③有效解决重排序问题
3、修饰对象
①修饰普通方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。
②修饰静态方法,其作用范围是这个静态方法,作用对象是这个类的所有对象
③修饰代码块,其作用范围是由{}括起来的代码块,作用的对象是调用这个代码块的对象
一个线程访问一个对象中的synchronize同步代码块时,试图访问该对象的线程将被阻塞
class SyncThread implements Runnable {
private static int count;
public SyncThread() {
count = 0;
}
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public int getCount() {
return count;
}
}
public class test {
public static void main(String[] args) {
SyncThread syncThread = new SyncThread();
Thread thread1 = new Thread(syncThread, "sycn1");
Thread thread2 = new Thread(syncThread, "sycn2");
thread1.start();
thread2.start();
}
}
上面的代码在控制台打印时依次等待执行,结果如下
sycn1:0
sycn1:1
sycn1:2
sycn1:3
sycn1:4
sycn2:5
sycn2:6
sycn2:7
sycn2:8
sycn2:9
当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象
我们把SyncThread的调用修改如下:
Thread thread1 = new Thread(new SyncThread(), "sycn1");
Thread thread2 = new Thread(new SyncThread(), "sycn2");
thread1.start();
thread2.start();
执行结果如下:
sycn1:0
sycn2:1
sycn1:2
sycn2:3
sycn2:5
sycn1:4
sycn2:6
sycn1:6
sycn1:8
sycn2:7
不是说一个线程执行synchronized代码块时其它的线程受阻塞吗?为什么上面的例子中thread1和thread2同时在执行?
这是因为synchronized只锁定对象,每个对象只有一个锁(lock)与之相关联,而上面的代码等同于下面这段代码:
SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();
这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行
问题答案:
问题1:不同步,因为a1.a和a2.a不是同一个锁,锁住的是this
问题2:同步,因为关键字static已经让这个代码块都添加上了同一把锁,锁住的是this.class