synchronize的两种用法

一、概念:

     1、对象锁

          包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)

     2、类锁

          指定synchronize修饰静态的方法或指定锁为class对象

二、用法

     1、对象锁

          (1)同步代码块

package com.zy.san.synSan;

/**
 * 
 * 
 * @author Administrator 对象锁实例1,代码块形式
 */
public class SynchronizedObectCodeBlock2 implements Runnable {

	static SynchronizedObectCodeBlock2 instance = new SynchronizedObectCodeBlock2();

	public static void main(String[] args) throws InterruptedException {
		Thread th1 = new Thread(instance);
		Thread th2 = new Thread(instance);
		th1.start();
		th2.start();
		while (th1.isAlive() || th2.isAlive()) {
		}
		System.out.println("finished");
	}

	@Override
	public void run() {
		synchronized (this) {

			// Thread.currentThread()当前线程,.getName()名字
			System.out.println("我是对象锁的代码块形式我叫" + Thread.currentThread().getName());
			try {
				// 让线程休眠3秒
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			System.out.println(Thread.currentThread().getName() + "运行结束");
		}
	}
}

 结合上面的代码猜猜看结果

synchronize的两种用法_第1张图片

可以看出它运行的顺序是一个对象运行完成后再运行的第二个对象

synchronize的两种用法_第2张图片

当我把synchronize注释掉后,两对象几乎是同时执行同时结束的,这就起不到保护的效果了。

               a、对象锁

     synchronize代码块使用的对象锁是this,如果遇到了非常复杂的业务逻辑是该怎么办了。

Object lock1=new Object();
	Object lock2=new Object();
	
	public void run() {
		synchronized (lock1) {

			// Thread.currentThread()当前线程,.getName()名字
			System.out.println("我是对象锁的代码块形式我叫" + Thread.currentThread().getName());
			try {
				// 让线程休眠3秒
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			System.out.println(Thread.currentThread().getName() + "运行结束");
		}
		synchronized (lock2) {

			// Thread.currentThread()当前线程,.getName()名字
			System.out.println("我是对象锁的代码块形式我叫" + Thread.currentThread().getName());
			try {
				// 让线程休眠3秒
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			System.out.println(Thread.currentThread().getName() + "运行结束");
		}
	}

可以指定自定义对象锁

synchronize的两种用法_第3张图片

运行结果3-4行,是同时运行的。是因为它们使用的不是同一个锁对象,它们不会串运行而是并运行。

如果它们使用同一个对象锁了?

synchronize的两种用法_第4张图片

               (2)方法锁:只能是修饰普通方法,对象锁默认为this

package com.zy.san.synSan;
/**
 * 
 * 
 * @author Administrator
 *对象锁实例2   方法锁形式 
 */
public class SynchronizedObectMethod3 implements Runnable{
	static SynchronizedObectMethod3 intance=new SynchronizedObectMethod3();
	public static void main(String[] args) {
		Thread th1=new Thread(intance);
		Thread th2=new Thread(intance);
		th1.start();
		th2.start();
		while(th1.isAlive() || th2.isAlive()){
			System.out.println("finished");
		}

	}
	public void run() {
		method();
	}
	public synchronized void method(){
		System.out.println("我是对象锁的方法修饰符形式,我叫:"+Thread.currentThread().getName());
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"结束");
	}

}

运行结果:

synchronize的两种用法_第5张图片

          2、类锁

               (1)概念:Java类可能有很多个对象,但只有1个class对象。

                          a、只有一个class对象:java类可能会有很多个对象,但是只有1个class对象。

                          b、本质:所以所谓的类锁,不过是class对象的锁而已。

                          c、用法和效果:类锁只能在同一时刻被一个对象拥有

                (2)形式1:synchronize加在static方法上。

package com.zy.san.synSan;

/**
 * 
 * @author Administrator 类锁的第一种形式,static形式(在方法上的)
 */
public class SynchronizedClassStatic4 implements Runnable {
	static SynchronizedClassStatic4 instance1 = new SynchronizedClassStatic4();
	static SynchronizedClassStatic4 instance2 = new SynchronizedClassStatic4();

	public static void main(String[] args) {
		Thread th1 = new Thread(instance1);
		Thread th2 = new Thread(instance2);
		th1.start();
		th2.start();
		while (th1.isAlive() || th2.isAlive()) {

		}
		System.out.println("finished");
	}

	public void run() {
		method();
	}

public static synchronized void method(){
	System.out.println("我是类锁的第一种形式,static形式,我叫:"+Thread.currentThread().getName());
	try {
		Thread.sleep(3000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	System.out.println(Thread.currentThread().getName()+"结束");
	}

}

执行结果:

synchronize的两种用法_第6张图片

这里最大的魔力就是static的运用,如果不使用static会出现什么情况了。

synchronize的两种用法_第7张图片

它就不会出现同步。

如果我在使用同步时是全局不止一个对象就要使用类锁的第一种形式static形式。

                (3)形式2:synchronize(*.class)代码块。

package com.zy.san.synSan;

/**
 * 
 * 
 * @author Administrator 我是类锁的第二种形式,synchronize(*.class)形式
 */
public class SynchronizeClassClass5 implements Runnable {
	static SynchronizeClassClass5 instanec = new SynchronizeClassClass5();
	static SynchronizeClassClass5 instanec2 = new SynchronizeClassClass5();

	public static void main(String[] args) {
		Thread th1 = new Thread(instanec);
		Thread th2 = new Thread(instanec2);
		th1.start();
		th2.start();
		while (th1.isAlive() || th2.isAlive()) {

		}
		System.out.println("finished");
	}

	@Override
	public void run() {
		method();

	}

	private void method() {
		synchronized (SynchronizeClassClass5.class) {
			System.out.println("我是类锁的第二种形式,synchronize(*.class),我叫" + Thread.currentThread().getName());
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"结束");
		}

	}

}

运行结果:

synchronize的两种用法_第8张图片

如果我将*.class改成this会如何了。

synchronize的两种用法_第9张图片

 

 

 

你可能感兴趣的:(实践)