前言
在多线程并发编程中Synchronized一直是元老级角色,大家都知道synchronized是重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,与lock相比性能相差并不是很大,还是比较建议同步的时候优先使用synchronized。
三种使用方式
修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁,同步代码块主要有三种方式 :synchronized(this)、synchronized (obj)、synchronized(Object.class),这三种方式分别是指同步本对象、同步其它对象、同步某个类。
修饰非静态实列方法
public class SynchronizedDemo {
public static void main(String[] args) {
SynchronizedDemo demo1 = new SynchronizedDemo();
// 修饰对象实列方法 锁定的当前实列对象 必须是公用同一个对象才行
new Thread("thread1"){
@Override
public void run(){
try {
demo1.demo1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread2"){
@Override
public void run(){
try {
demo1.demo1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 修饰实列方法
* @throws InterruptedException
*/
public synchronized void demo1() throws InterruptedException{
System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
//休眠2s 造成两个线程同时访问本实列方法
Thread.sleep(2000);
}
- 修饰静态方法 同步的是方法所在的类对象
public class SynchronizedDemo {
public static void main(String[] args) {
/**
* 修饰对象静态方法
* 静态方法是类方法 静态方法即类方法,它属于一个类而不是某个对象
* 在其上面加锁 锁的对象为类对象
*/
new Thread("thread2-1"){
@Override
public void run(){
try {
SynchronizedDemo.demo2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread2-2"){
@Override
public void run(){
try {
SynchronizedDemo.demo2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
/**
*修饰静态方法
* @throws InterruptedException
*/
public synchronized static void demo2() throws InterruptedException{
System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
Thread.sleep(2000);
}
}
- 修饰代码块 同步代码块主要有三种方式 :synchronized(this)、synchronized (obj)、synchronized(Object.class),这三种方式分别是指同步本对象、同步其它对象、同步某个类。
public class SynchronizedDemo {
public static void main(String[] args) {
/**
* 修饰当前对象代码块
* 锁的调用方法的当前对象
* 代码块 this代表当前对象
* 3与1 2 不是同一个对象 13同时执行 12是同步执行
*/
SynchronizedDemo block = new SynchronizedDemo();
new Thread("thread1-1"){
@Override
public void run(){
try {
new SynchronizedBlock(block).demo3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread1-2"){
@Override
public void run(){
try {
new SynchronizedBlock(new SynchronizedDemo()).demo3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread1-3"){
@Override
public void run(){
try {
new SynchronizedBlock(block).demo3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
/**
* 修饰对象实列方法-代码块-指定对象
* 这里new了两个SynchronizedBlock对象 但由于指定同步对象是SynchronizedDemo
* 所以方法依然会同步执行
*/
SynchronizedDemo demo4 = new SynchronizedDemo();
new Thread("thread4-1"){
@Override
public void run(){
try {
new SynchronizedBlock(demo4).demo3_1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread4-2"){
@Override
public void run(){
try {
new SynchronizedBlock(demo4).demo3_1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
/**
* 修饰代码块-class
* 这里new了两个SynchronizedDemo对象 但锁的是类对象
* 所以方法依然会同步执行
*/
new Thread("thread3-1"){
@Override
public void run(){
try {
new SynchronizedBlock(new SynchronizedDemo()).demo3_2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("thread3-2"){
@Override
public void run(){
try {
new SynchronizedBlock(new SynchronizedDemo()).demo3_2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
class SynchronizedBlock {
//声明一个实例变量
private SynchronizedDemo demo;
SynchronizedBlock(SynchronizedDemo demo){
this. demo= demo;
}
/**
* 同步当前对象
* @throws InterruptedException
*/
public void demo3() throws InterruptedException{
synchronized(this){
System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
Thread.sleep(2000);
}
}
/**
* 同步指定对象
* @throws InterruptedException
*/
public void demo3_1() throws InterruptedException{
synchronized(demo){
System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
Thread.sleep(2000);
}
}
/**
* 同步class类对象
* @throws InterruptedException
*/
public void demo3_2() throws InterruptedException{
synchronized(SynchronizedDemo.class){
System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
Thread.sleep(2000);
}
}
}
总结
- 在多线程环境中,可以使用synchronized关键字对资源进行同步,synchronized关键字可以同步方法和代码块,同步的是对象或者类,而不是代码。
- 一个对象中的同步方法一次只能被一个线程访问,如果有多个同步方法,一个线程一次也只能访问其中的一个同步方法,但是非同步方法不受任何影响。
- 同步是通过加锁的形式来控制的,让一个线程访问一个同步方法时会获得这个对象的锁,只有退出同步方法时才会释放这个锁,其它线程才可访问