声明
- 本人测试代码,放在本文末尾,复制可用
- 为方便说明,前面主要以图片为主,进行示例
synchronized关键字实现线程同步的方式有
-
使用同步方法
-
使用同步代码块儿
关键概念说明
任何Object都有且仅有一个属于它自己的内置锁,这个内置锁是互斥的;当线程需要访问这个Objcet的任何一个需要内置锁的方法或任何一个指定需要这个Objcet的内置锁的同步代码块儿时,这个线程必须先抢占到这个Object的内置锁才能访问。当同步方法或同步代码块儿执行完毕之后,马上释放这个对象的锁,再进行新的一轮的抢占。
注:被synchronized关键字修饰的方法或代码块儿,就表示访问时需要内置锁。
注:同步方法释放锁的时机是:该同步方法执行完毕;
同步代码块儿释放锁的时机是:该同步代码块儿执行完毕(无论该同步代码块儿所在的方法是否执行完毕)。
按照Object不同,我们一般又分为对象锁与类锁(注:类锁只是一个抽象性概念)
注:一个类只有且只有一个属于自己的类锁;如果一个类实例了多个对象,那么每个对象有且只有一个属于它们自己的对象锁。
注:如果一个对象锁或者类锁被某一个线程抢占到了,并不会影响其他线程访问这个对象或这个类的那些没有被锁上(没有synchronized关键字)的方法、没有被锁上(没有synchronized关键字)的代码块儿。
注:类锁与对象锁并不互斥,即:一个线程获得了一个类的一个实例对象的对象锁,那么并不影响其他线程获得该类的类锁。
使用时,代码总体说明
需要类锁的情况
1.synchronized作用在静态方法上
2.synchronized用于同步代码块儿,但是指定类锁
需要对象锁的情况
1.synchronized作用在普通方法上
2.synchronized用于同步代码块儿,但是指定这个对象
使用synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁
使用时,代码详细说明
先看一下MyThread类的继承实现关系,为下面做铺垫:
代码详细说明正式开始
调用被synchronized修饰的静态方法---[测试类锁]
要被调用的方法:
main测试方法:
某次输出结果为:
注:这两个方法都需要同一个锁,所以线程就会进行抢占、就会发生线程等待、堵塞等情况。(为了快速测试,本人只写了一个被synchronized修饰的静态方法来测试)。
注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法、是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况。
synchronized用于同步代码块儿,但是指定类锁---[测试类锁]
要被调用的方法:
和
main测试方法:
某次输出结果为:
注:由于这个类的实例方法synchronizedCodeBlockTest4中的代码块儿指定了需要类锁,而静态方法也需要类锁,所以这里线程就需要抢占、就会发生线程等待、堵塞等情况。
注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法、是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况。
synchronized作用在普通方法上---[测试对象锁]
要被调用的方法:
main测试方法:
某次输出结果为:
注:测试对象锁时,创建线程要用同一个对象来创建.因为:一个类的不同实例对象,都有一个属于自己的对象锁,我们要测试,就需要同一个对象来创建线程。
注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法、是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况。
synchronized用于同步代码块儿,但是指定对象锁---[测试对象锁]
要被调用的方法:
和
main测试方法:
某次输出结果为:
注:测试对象锁时,创建线程要用同一个对象来创建.因为:一个类的不同实例对象,都有一个属于自己的对象锁,我们要测试,就需要同一个对象来创建线程。
注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法、是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况。
测试同步代码块儿 ,抢占锁的时机
要被调用的方法:
和
main测试方法:
多次运行main方法,其中两次输出结果:
某一次输出:
某一次输出:
注:synchronized修饰方法时,在进入方法时,就需要锁;方法执行完毕之后,才释放锁。
注:这里是以需要对象锁的代码块儿测试的,经测试,需要类象锁的代码块儿也遵循此原则。
注:synchronized修饰同步代码块儿时,在进入代码块儿所在的方法时,暂时不需要锁;但是在执行到该代码块儿时,需要放锁,当代码块儿执行完毕之后,马上释放锁(无论此时代码块儿所在的方法是否执行完)。
测试同步代码块儿 ,释放锁的时机
要被调用的方法:
和
main测试方法:
某次输出结果为:
注:synchronized修饰方法时,在进入方法时,就需要锁;方法执行完毕之后,才释放锁。
注:这里是以需要对象锁的代码块儿测试的,经测试,需要类象锁的代码块儿也遵循此原则。
注:synchronized修饰同步代码块儿时,在进入代码块儿所在的方法时,暂时不需要锁;但是在执行到该代码块儿时,需要放锁,当代码块儿执行完毕之后,马上释放锁(无论此时代码块儿所在的方法是否执行完)。
使用synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁
要被调用的方法:
和
main函数为:
某次输出结果为:
注:我们使用关键字synchronized时,一般指明都是指明需要对象或类的锁;但有时这样并不能满足我们的需求,此时我们就可以考虑使用上述方式。
再如:
此时,synchronized (hashtable)就意味着,需要抢占对象锁或者抢占类锁了。具体哪些同步方法、哪些同步代码块儿需要锁,这里就不再赘述了。
类锁与对象锁 互不影响 --- 测试
要被调用的方法:
和
main函数为:
某次输出结果为:
注:我们使用关键字synchronized时,一般指明都是指明需要对象或类的锁;但有时这样并不能满足我们的需求,此时我们就可以考虑使用上述方式。
给出本次测试代码
/**
* 多线程synchronized关键字---使用测试
*
* @author JustryDeng
* @Date 2018年8月27日 上午11:06:40
*/
public class MyThread implements Runnable {
/**
* 同步方法:synchronized作用在普通方法上(需要这个类的实例对象的对象锁)
*
* @Date 2018年8月27日 下午4:47:16
*/
public synchronized void synchronizedMethodTest1() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
/**
* 同步方法:synchronized作用在静态方法上(需要这个类的类锁)
*
* @Date 2018年8月27日 下午4:47:16
*/
public static synchronized void synchronizedMethodTest2() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
/**
* 同步代码块儿:synchronized指明需要的类的实例this的对象锁(需要这个类的实例对象的对象锁)
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest3() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
/**
* 同步代码块儿:synchronized指明需要的类的实例this的对象锁
* 测试:同步代码块儿 抢占锁的时机
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest33() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t synchronized开始前" + i);
}
synchronized (this) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
/**
* 同步代码块儿:synchronized指明需要的类的实例this的对象锁
* 测试:同步代码块儿 释放锁的时机
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest333() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t synchronized结束后" + i);
}
}
/**
* 同步代码块儿:synchronized指明需要的类锁为MyThread.class(即:需要MyThread这个类的类锁)
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest4() {
synchronized (MyThread.class) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
private String string = "i have a lock!";
// private Hashtable<String, Object> hashtable = new Hashtable<String, Object>();
/**
* 同步代码块儿:synchronized可以指定任意 非null的 对象作为锁(不限于类、实例对象)
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest5() {
synchronized (string) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
/**
* 同步代码块儿:synchronized可以指定任意 非null的 对象作为锁(不限于类、实例对象)
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedCodeBlockTest6() {
synchronized (string) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
/**
* 普通方法
*
* @Date 2018年8月27日 下午4:47:16
*/
public void synchronizedNormalMethodTest7() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
@Override
public void run() {
System.out.println("重写run()");
}
/*
* 类锁 与 对象锁 互不影响
*/
public static void main(String[] args) {
MyThread mt= new MyThread();
Thread t1 = new Thread(new Runnable() {
public void run() {
mt.synchronizedMethodTest1();
}
}, "线程one");
Thread t2 = new Thread(new Runnable() {
public void run() {
MyThread.synchronizedMethodTest2();
}
}, "线程two");
t1.start();
t2.start();
}
// /*
// * 同步代码块儿:synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest5();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest6();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * 测试同步代码块儿 ,释放锁的时机
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedMethodTest1();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest333();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * 测试同步代码块儿 ,抢占锁的时机
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedMethodTest1();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest33();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * synchronized用于同步代码块儿,但是指定对象锁---[测试对象锁]
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedMethodTest1();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest3();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * synchronized作用在普通方法上---[测试对象锁]
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedMethodTest1();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedMethodTest1();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * synchronized用于同步代码块儿,但是指定类锁---[测试类锁]
// */
// public static void main(String[] args) {
// MyThread mt= new MyThread();
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// MyThread.synchronizedMethodTest2();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// mt.synchronizedCodeBlockTest4();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
// /*
// * 调用被synchronized修饰的静态方法---[测试类锁]
// */
// public static void main(String[] args) {
// Thread t1 = new Thread(new Runnable() {
// public void run() {
// MyThread.synchronizedMethodTest2();
// }
// }, "线程one");
//
// Thread t2 = new Thread(new Runnable() {
// public void run() {
// MyThread.synchronizedMethodTest2();
// }
// }, "线程two");
//
// t1.start();
// t2.start();
// }
}