需求:创建一个服装店对象实例,用两个线程模拟两个人同时进店挑衣服->试衣服->买衣服的过程。
代码:
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效率更高。