文章目录
1、synchronized 锁住的是什么?
首先:
synchronized(obj) { /* 同步代码块 */}
中的obj
相当于一个锁,它可以是任意对象。当线程任务中需要多个同步时,必须通过锁来区分。举个栗子:
-
线程 A 和线程 B ,A 和 B 共同操作一段数据共享的代码。当 A 和 B 并发修改同一个共享数据时,如果 CPU 恰好在 A 没有执行完该任务就已经切换到了正在修改此数据的 B ,当在切换回 A 时,就会造成最终结果异常。
-
这种问题的原因在于,A 和 B 在同时操作同一个数据,也即是,同时执行任务。那么,解决思路就是,让 A 彻底执行完含有共享数据的代码后,再让 CPU 切换到 B 去执行。
-
这便引入了
synchronized
。 -
synchronized { /* 同步代码块 */}
中,用大括号将对共享数据操作的代码单独围起来,当 A 和 B 进入到{}
时,A 和 B 开始执行这段任务。 -
怎么让 A 在执行任务还没有结束的时候,B 不会进去插一杠呢?
-
这便引入了对象锁
obj
。 -
obj
像一个监视者,所有的线程都要在门口接受它的“盘查”。当 A 进入{}
之前,先获取“监视者”obj
给予的进入资格,只要 A 没执行结束,就全程盯着 A。这样,当 B 想进来的时候,因为obj
去盯着 A 了,没空管 B ,B 就获取不到进入{}
的资格,当然只能等obj
盯完梢回来后再给予 B 进门的资格了,这时候,A 已经执行完对共享数据的操作了,B 再进去的时候,就不会出现上述问题了。 -
这就是多线程的同步。
-
任何人都可以成为“监视者”(
obj
可以是任意对象),但“监视者”只能有一个(多线程来访时,面对的必须是同一个obj
对象)。试想一下,如果 A 进去时,已经去了一个“监视者”,B 在 A 没有出来的时候又遇见了一个“监视者”,它给予了 B 进入的权利,这样,A 和 B不就同时进去操作了嘛。public class ThreadSafeDemo1 { public static void main(String[] args) { Demo1 d = new Demo1(); Thread thread1 = new Thread(d); Thread thread2 = new Thread(d); thread1.start(); thread2.start(); } } class Demo1 implements Runnable { private int a = 200; // 比如,这里自定义创建一个锁对象为 object private Object object = new Object(); @Override public void run() { while (true) { /** * 堆内存中只创建了一个object对象, * 无论如何,synchronized锁住的都是object这一个对象, * 所有的线程进来都要被这同一个对象“监察” * * 最终输出的结果符合预期结果 */ synchronized (obj) { if (a > 0) { try { <