多线程以及同步问题
1.单例中的线程安全问题
在单例设计模式中,会出现多线程的同步问题。主要表现在,当使用的是懒汉式单例设计模式来创建对象的时候,若有多个进程同时在执行,则有可能会创建了多个对象,但这个不是单例设计模式应该出现的问题。所以需要使用锁机制来解决。需要注意的是,饿汉式不会出现这个问题。具体代码如下。
1 class Singleton_lazy{ 2 //懒汉式 3 private Singleton_lazy(){} 4 5 private static Singleton_lazy INSTANCE = null; 6 7 public static Singleton_lazy getInstance(){ 8 if(INSTANCE == null){ //在同步代码块的上面加一个判断,若对象不为空,则肯定不需要创建对象了。也就不需要再去通过同步代码块了 9 synchronized (Singleton_lazy.class) { //因为是静态的方法,没有办法使用this去作为锁的对象,因此可以使用类名.class 10 if (INSTANCE == null) 11 INSTANCE = new Singleton_lazy(); 12 } 13 } 14 return INSTANCE; 15 } 16 }
姑且也许可以这么认为,在有判断语句存在的地方,由于多线程是由cpu来控制执行的,时间片的切换可能导致一种不安全的情况,例如
1 boolean flag = false; 2 if(flag == false){ 3 ....execute; 4 flag = true; 5 }
在这种情况下,第一个线程满足条件进入之后,还没来得及将flag改为true,此时第二条进程已经通过了判断,进入了函数体,导致不安全问题的产生。
2.死锁问题
1 public class _02_DeadLock { 2 3 public static void main(String[] args) throws Exception { 4 //创建一个任务类的对象 5 DeadLockTask task = new DeadLockTask(); 6 //创建线程类对象 7 /* 8 * 如果这样去写死锁的话,会出现一个问题, 9 * 一旦中国人或者美国人拿到了第一次的线程的执行权限,那么就会一直拿下去,另一个进程就没有机会再能够拿到了。并且让标记改为false,这样就 10 * 有可能进入到美国人线程的循环中 11 * 因此:当中国人线程开始执行之后,让主线程睡一会儿。这样的话,另一个线程就有机会能够执行。 12 */ 13 Thread chineseThread = new Thread(task,"中国人线程"); 14 Thread americanThread = new Thread(task,"美国人线程"); 15 chineseThread.start(); 16 Thread.sleep(1000); //这边要让主线程睡一会儿,才能够让后面的线程有机会执行。 17 task.flag = false; 18 americanThread.start(); 19 } 20 21 } 22 23 //创建一个死锁任务类 24 class DeadLockTask implements Runnable{ 25 //属性 26 //定义一个flag用来记录到底是中国人还是美国人,true代表中国人 27 boolean flag = true; 28 //此时定义两个锁对象 29 Object Chopsticks = new Object(); 30 Object KnifeAndFork = new Object(); 31 //行为 32 @Override 33 public void run() { 34 //死锁的主要的产生的原因就是同步嵌套了同步。那么为了形成死锁,我们这边要人为制造同步的嵌套 35 //注意:而且不能只拿一次就结束了。要制造一个无限的一直去拿的情况 36 if(flag){ 37 while(true){ 38 synchronized (Chopsticks){ 39 System.out.println(Thread.currentThread().getName() + "chinese...get...chopsticks"); 40 synchronized(KnifeAndFork){ 41 System.out.println(Thread.currentThread().getName() + "chinese...get....knifeandfork"); 42 } 43 } 44 } 45 }else{ 46 while(true){ 47 synchronized(KnifeAndFork){ 48 System.out.println(Thread.currentThread().getName() + "american...get...knifeandfork"); 49 synchronized(Chopsticks){ 50 System.out.println(Thread.currentThread().getName() + "american...get...chopsticks"); 51 } 52 } 53 } 54 } 55 } 56 }