java并发编程 笔记四

阻塞式的解决方案synchronized

语法:

synchronized(对象) // 线程1, 线程2(blocked)
{
 临界区
}

解决

static int counter = 0;
static final Object room = new Object();

public static void main(String[] args) throws InterruptedException {
 Thread t1 = new Thread(() -> {
 	for (int i = 0; i < 5000; i++) {
 		synchronized (room) {
 			counter++;
 			}
 		}
 	}, "t1");
 Thread t2 = new Thread(() -> {
 	for (int i = 0; i < 5000; i++) {
 		synchronized (room) {
 			counter--;
 		}
 	}
 }, "t2");
 
 t1.start();
 t2.start();
 t1.join();
 t2.join();
 log.debug("{}",counter);
}

类比

如何理解这个synchronized(对象){},可以把这个对象想象成一个room(房间),有唯一的入口,一次只能进入一个人:

1、这时候有两个人,小明,小红(t1,t2)。当线程 t1 执行到 synchronized(room) 时就好比 小明(t1) 进入了这个房间,并锁住了门拿走了钥匙,在门内执行count++代码。

2、这时候如果 小红(t2) 也运行到了 synchronized(room) 时,它发现门被锁住了,只能在门外等待,发生了上下文切换,阻塞住了。

3、这中间即使 t1 的 cpu 时间片不幸用完,被踢出了门外(不要错误理解为锁住了对象就能一直执行下去哦),这门还是锁住的,小明(t1) 仍拿着钥匙,小红(t2) 线程还在阻塞状态进不来,只有下次轮到 小明(t1) 自己再次获得时间片时才能开门进入。

4、当小明(t1) 执行完 synchronized{} 块内的代码,这时候才会从 obj 房间出来并解开门上的锁,唤醒 小红(t2) 线程把钥匙给他。小红(t2) 线程这时才可以进入 obj 房间,锁住了门拿上钥匙,执行它的 count--代码


synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断。(这是啥啊?)

  • 如果把 synchronized(obj) 放在 for 循环的外面,如何理解?-- 原子性1
  • 如果 t1 synchronized(obj1) 而 t2 synchronized(obj2) 会怎样运作?-- 锁对象
  • 如果 t1 synchronized(obj) 而 t2 没有加会怎么样?如何理解?-- 锁对象

方法上的 synchronized

synchronized还可以写到方法上,也同样能锁住对象,不能锁住方法。

class Test{
 public synchronized void test() {

 }
}
//等价于
class Test{
 public void test() {
 	synchronized(this) {

 	}
 }
}

synchronized()加在静态方法上,相当于锁住类对象,而不是锁住this对象

class Test{
 public synchronized static void test() {
 }
}
//等价于
class Test{
 public static void test() {
	 synchronized(Test.class) {

	 }
 }
}

不加 synchronized 的方法

不加 synchronzied 的方法就好比不遵守规则的人,不去老实排队(好比翻窗户进去的)

对synchronized有兴趣的同学可以去做做线程八锁


  1. 程序的原子性指:整个程序中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。 ↩︎

发布了93 篇原创文章 · 获赞 31 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43866567/article/details/104535816