每一个对象在出生的时候就有一把钥匙(监视器Monitor),那么被synchronized 修饰的方法至关于给方法加了一个锁,这个方法就能够进行同步,在多线程的时候,不会出现线程安全问题。java
注:Monitor是 Java中用以实现线程之间的互斥与协做的主要手段,它能够当作是对象或者 Class的锁。每个对象都有,也仅有一个 Monitor。安全
下面经过一张图片进行讲解:多线程
图片看不清,请点击这里 : 高清大图ide
import java.util.Date; /** * 测试的object类 * * @author:dufy * @version:1.0.0 * @date 2017/9/29 * @email 742981086@qq.com */ public class ObjectTest { public synchronized void methodA(){ try { System.out.println("This is methodA ...." + Thread.currentThread().getName() + ": " + new Date()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public void methodB(){ System.out.println("This is methodB ...." + Thread.currentThread().getName() + ": " + new Date()); } public synchronized void methodC(){ try { System.out.println("This is methodC ...." + Thread.currentThread().getName() + ": " + new Date()); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.dufy.concurrentcode; /** * 测试线程类 * * @author:dufy * @version:1.0.0 * @date 2017/9/29 * @email 742981086@qq.com */ public class ThreadTest extends Thread{ public static void main(String[] args) { ObjectTest ot = new ObjectTest(); Thread1 t1 = new Thread1(ot,"thread1"); Thread2 t2 = new Thread2(ot,"thread2"); Thread3 t3 = new Thread3(ot,"thread3"); Thread4 t4 = new Thread4(ot,"thread4"); t1.start(); t2.start(); t3.start(); t4.start(); } static class Thread1 extends Thread{ private ObjectTest objectTest; public Thread1(ObjectTest objectTest,String name){ setName(name); this.objectTest = objectTest; } @Override public void run() { super.run(); objectTest.methodA(); } } static class Thread2 extends Thread{ private ObjectTest objectTest; public Thread2(ObjectTest objectTest,String name){ setName(name); this.objectTest = objectTest; } @Override public void run() { super.run(); objectTest.methodB(); } } static class Thread3 extends Thread{ private ObjectTest objectTest; public Thread3(ObjectTest objectTest,String name){ setName(name); this.objectTest = objectTest; } @Override public void run() { super.run(); objectTest.methodA(); } } static class Thread4 extends Thread{ private ObjectTest objectTest; public Thread4(ObjectTest objectTest,String name){ setName(name); this.objectTest = objectTest; } @Override public void run() { super.run(); objectTest.methodC(); } } }
运行结果:函数
This is methodB ....thread2: Fri Sep 29 23:21:17 CST 2017 This is methodA ....thread1: Fri Sep 29 23:21:17 CST 2017 This is methodC ....thread4: Fri Sep 29 23:21:18 CST 2017 This is methodA ....thread3: Fri Sep 29 23:21:21 CST 2017
注:
一、运行的结果可能和上图讲的线程流程不一样,没有关系,只要理解对象锁和synchronized的核心思想就好,线程的运行原本就是具备随机性这个特色。
二、此段代码是同步方法,其实同步的代码块也是一个道理,同步代码块用synchronized(this)时候,当一个线程访问object的一个synchronized(this)同步代码块的时候,其余线程对object中全部其余的synchronized(this)同步的代码块访问都被阻塞 (阻塞的是同步代码块,线程依然能够进入同步代码块的方法)。测试
首先看一下线程和 Monitor之间关系,以 及线程的状态转换图。经过图讲解一下整个过程。this
上图分为三块:Entry Set(进入区) 、The Owner(拥有区)、Wait Set(等待区)。spa
Entry Set(进入区):表示线程经过synchronized要求获取对象的锁。若是对象未被锁住,则迚入拥有者;不然则在进入区等待。一旦对象锁被其余线程释放,当即参与竞争。.net
The Owner(拥有区):表示某一线程成功竞争到对象锁。线程
Wait Set(等待区):表示线程经过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。
从图中能够看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。