Java 中的每个对象都有一个与之关联的内部锁(Intrinsic lock). 这种锁也称为监视器(Monitor), 这种内部锁是一种排他锁,可以保障原子性,可见性与有序性.。
内部锁是通过 synchronized 关键字实现的.synchronized 关键字修饰代码块,修饰该方法。
修饰代码块的语法:
synchronized( 对象锁 ) {
同步代码块,可以在同步代码块中访问共享数据
}
修饰实例方法就称为同步实例方法。
修饰静态方法称称为同步静态方法。
例示代码如下:
A.同步代码块
1.使用this作为锁对象:
package com.company.intrinsiclock;
/*
* synchronized同步代码块
* this锁对象
* */
public class Test01 {
public static void main(String[] args) {
//创建两个线程,分别调用mm()方法
//先创建Test01对象,通过对象名调用mm()方法
Test01 obj=new Test01();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象this就是obj对象
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象this就是obj对象
}
}).start();
}
//定义方法,设置同步代码块
public void mm(){
synchronized (this) {//通常使用this当前对象作为锁对象
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
}
2.线程的锁不同,不能实现同步,想要同步必须使用同一个锁对象
package com.company.intrinsiclock;
/*
* synchronized同步代码块
* this锁对象,如果线程的锁不同,不能实现同步,想要同步必须使用同一个锁对象
* */
public class Test02 {
public static void main(String[] args) {
Test02 obj=new Test02();
Test02 obj2=new Test02();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象this是obj对象
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj2.mm();//使用的锁对象this是obj2对象,与第一个线程的锁对象不同,不能实现同步
}
}).start();
}
//定义方法,设置同步代码块
public void mm(){
synchronized (this) {//通常使用this当前对象作为锁对象
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
}
3.使用常量对象作为锁对象
package com.company.intrinsiclock;
/*
* synchronized同步代码块
* 使用常量对象作为锁对象
* */
public class Test03 {
public static void main(String[] args) {
Test03 obj=new Test03();
Test03 obj2=new Test03();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象使用的锁对象是OBJ常量
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj2.mm();//使用的锁对象使用的锁对象是OBJ常量
}
}).start();
}
//定义一个常量作为锁对象
public static final Object OBJ=new Object();
//定义方法,设置同步代码块
public void mm(){
synchronized (OBJ) { //也可以使用常量对象作为锁对象,此时即使两个线程的对象不同也可以实现同步
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
}
4.使用常量对象作为锁对象时,同步代码块代码与其所在的位置无关,因为是同一个锁对象
package com.company.intrinsiclock;
/*
* synchronized同步代码块
* 使用常量对象作为锁对象,方法体代码与其所在的位置无关,只要是同一个锁对象
* */
public class Test04 {
public static void main(String[] args) {
Test04 obj=new Test04();
Test04 obj2=new Test04();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象this是obj对象
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj2.mm();//使用的锁对象OBJ常量
}
}).start();
//第三个线程调用的是静态方法
new Thread(new Runnable() {
@Override
public void run() {
sm();//使用的锁对象OBJ常量
}
}).start();
}
//定义一个常量作为锁对象,方法体代码与其所在的位置(实例方法或者静态方法)无关,只要是同一个锁对象
public static final Object OBJ=new Object();
//定义方法,设置同步代码块
public void mm(){
synchronized (OBJ) { //使用的锁对象OBJ常量
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
//定义静态方法,设置同步代码块
public static void sm(){
synchronized (OBJ) { //也可以使用常量对象作为锁对象,此时即使两个线程的对象不同也可以实现同步
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
}
B.同步方法
1.同步实例方法
package com.company.intrinsiclock;
/*
* synchronized同步实例方法
*只要是同一个锁对象就可以实现同步
* */
public class Test0 {
public static void main(String[] args) {
//创建两个线程,分别调用mm()方法,mm22()方法
//先创建Test01对象,通过对象名调用mm()方法
Test0 obj=new Test0();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象this就是obj对象
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj.mm22();//使用的锁对象this就是obj对象
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
new Test0().mm22();//使用的锁对象this不是obj对象,不可以实现同步
}
}).start();
}
//定义方法,设置同步代码块
public void mm(){
synchronized (this) {//通常使用this当前对象作为锁对象
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
//使用synchronized修饰设置同步实例方法,默认this作为锁对象
public synchronized void mm22(){
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
2.同步静态方法
package com.company.intrinsiclock;
/*
* synchronized同步静态方法
*只要是同一个锁对象就可以实现同步,默认的锁对象是当前类的运行时类对象,如Test06.class,有人称他为类锁
* */
public class Test06 {
public static void main(String[] args) {
//创建两个线程,分别调用mm()方法,mm22()方法
//先创建Test01对象,通过对象名调用mm()方法
Test06 obj=new Test06();
//创建两个线程并启动
new Thread(new Runnable() {
@Override
public void run() {
obj.mm();//使用的锁对象是Test06.class
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
obj.sm22();//使用的锁对象也是Test06.class
}
}).start();
}
//定义方法,设置同步代码块
public void mm(){
//使用当前类的运行时类对象作为锁对象,可以简单的理解为把Test06的字节码文件作为锁对象
synchronized (Test06.class) {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
//使用synchronized修饰设置同步静态方法,默认当前运行时类Test06.class作为锁对象
public synchronized static void sm22(){
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}