JAVA多线程之单例模式

1,饿汉模式代码:

public class SingleTest {
	private static SingleTest instance = new SingleTest();
	
	private SingleTest(){
		
	}
	
	public SingleTest getInstance(){
		return instance;
	}
}

2,懒汉模式代码:

public class SingleTest {

	private static SingleTest instance = null;
	private SingleTest(){
		
	}
	public SingleTest getInstance(){
		if(null == instance)
			instance = new SingleTest();
		return instance;
	}
}

3,懒汉模式中存在的多线程安全性问题

当有多个线程同时执行到if语句判断时:线程A执行if判断 instace==null;CPU切换到线程B执行,线程B执行if判断 instance==null,这样就 new 了两个SingleTest对象。线程B new 的SingleTest对象更改了线程A new 的SingleTest对象的引用。

if(null == instance)
	instance = new SingleTest();
改进:

public class SingleTest {

	private static SingleTest instance = null;
	private SingleTest(){
		
	}
	public SingleTest getInstance(){
		if(null == instance)
			synchronized (SingleTest.class) {
				if(null == instance)
					instance = new SingleTest();
			}
		return instance;
	}
}

使用了static 锁进行同步。 当有多个线程同时执行到if语句判断时(第一个if语句):线程A执行if判断 instace==null;CPU切换到线程B执行,线程B执行if判断 instance==null。但是只有一个线程能够获得 static 锁进入同步代码块,当第一个线程进入同步代码块后 new 了SingleTest对象,后面的进程再进入同步代码块时,进行if判断为假,就不会再创建第二个SingleTest对象了。

4,饿汉模式与线程安全的懒汉模式比较

①二者都是线程安全的。对于饿汉模式而言,它在JVM加载该类时就已经创建好SingleTest对象了,因此有多个线程调用getInstance()时始终只有一个SingleTest对象存在。

②不管需不需要SingleTest对象,只要一加载SingleTest.java类,就会创建SingleTest对象,比如:假设SingleTest类中还定义了其他静态方法,通过类名.静态方法名() 调用静态方法时,会创建SingleTest对象,尽管此时并不需要使用SingleTest的实例对象。

若创建SingleTest对象开销很大,则有性能问题。而对于懒汉模式而言,只有在需要SingleTest对象时,才会创建,因为它是通过调用getInstance方法,然后在该方法里面new的对象;而对于饿汉模式,SingleTest对象在加载时已经生成,getInstance()方法只是负责返回该对象。


5,其他的一些多线程问题

①static 锁 与 this 锁

静态同步方法与同步方法 使用的锁

静态同步方法使用的是static锁。调用静态同步方法相当于获得了一个以 类名.class 的锁,如下:

synchronized (SingleTest.class) {//static 锁
    //processing....
    }

同步方法使用的是this锁。调用同步方法相当于获得了一个当前对象的锁。因为对于方法而言,是通过 对象.方法名进行调用的,即该方法被调用时,一定是某个对象调用了它,同步方法就获得了该对象的锁,如下:

synchronized(this){
	//processing
}

②线程执行了Thread.sleep(long)方法时,不会释放它所占有的锁。(注意:没有不带参数的sleep()方法)

private Object lock = new Object();
public void run(){
	while(true)
	{
		synchronized(lock){
			//do some processing
			try{
				Thread.sleep(100);
			}catch(InterruptedException e){
				
			}
			//do another processing
		}
	}
}
当线程获得了 lock锁进行了一些处理,然后睡眠100ms。当它执行sleep(100)后,会放弃CPU,进入阻塞状态。但是,它不会释放占有的 lock 锁。只有当它睡眠100ms后,重新获得CPU,再执行完另一些处理退出syncronized代码块之后,才会释放 lock 锁。


多线程入门资料参考:JAVA 多线程编程深入详解--汪文君

你可能感兴趣的:(JAVA)