并发学习笔记(二):synchronized代码块

需求:创建一个服装店对象实例,用两个线程模拟两个人同时进店挑衣服->试衣服->买衣服的过程。

代码:

public class ShopDemo {
	public static void main(String args[]){
		Shop shop = new Shop();
		Thread t1 = new Thread(shop);
		Thread t2 = new Thread(shop);
		
		t1.start();
		t2.start();
	}
}

class Shop implements Runnable{
	public void run(){
		Thread t = Thread.currentThread();
		System.out.println(t+"..."+"正在挑衣服……");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t+"..."+"正在试衣服……");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t+"..."+"正在买衣服……");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("买完辣");
	}
}

运行时,发现两个人在一起试衣服。比较尴尬,现实中不会允许这种情况出现,所以为了避免一起试衣服。所以将run方法加了synchronized关键字。

但是运行过程中,又出现了“必须分别挑衣服和分别买衣服”的状况,而在现实生活中,两个人一起挑衣服->试衣服->买衣服的过程,真正需要分开的只有“试衣服”的阶段。所以需要只给“试衣服”实现同步。

方法:使用synchronized代码块

		synchronized(this){
			System.out.println(t+"..."+"正在试衣服……");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
代码块后面括号中需要传入一个对象,表示“锁”,也就是说,想要访问此代码块的线程必须要拿到相应的实例。否则阻塞。

进一步理解函数中的synchronized声明:其实就是给函数加了调用此函数的对象的Class实例。

所以:

1.如果是synchronized字段修饰的静态方法,不管有多少个实例对象,都是同步的(因为锁只有一个,为虚拟机加载此类时产生的Class实例)。

2.同一个实例中多个以synchronized修饰的方法也是同步的(同样也是因为锁只有一个,为该对象的实例)。


StringBuffer和StringBuilder的区别:StringBuffer是线程安全的,StringBuilder不是。所以在动用多个线程调用一个时,应选用StringBuffer,防止乱码产生(几个线程轮流操作导致内容错乱)。而StringBuilder效率更高。


你可能感兴趣的:(笔记,java)