JAVA自学教程之单例设计模式涉及的多线程问题。
一、多线程下的单例设计模式
利用双重判断的形式解决懒汉式的安全问题和效率问题
- //饿汉式
- /*class Single
- {
- private static final Single t = new Single();
- private Single(){} //private构造函数,确保其他类对象不能直接new一个该对象实例
- public static Single getInstance()
- {
- return t;
- }
- }
- */
- //懒汉式
- class Single
- {
- private static Single t = null;
- private Single(){}
- public static Single getInstance() //同步函数就没必要了,同步整个函数致使效率降低
- {
- if(t==null)//解决效率问题
- {
- synchronized(Single.class)//解决安全问题
- {
- if(t==null)
- t = new Single();
- }
- }
- return t;
- }
- }
//饿汉式 /*class Single { private static final Single t = new Single(); private Single(){} //private构造函数,确保其他类对象不能直接new一个该对象实例 public static Single getInstance() { return t; } } */ //懒汉式 class Single { private static Single t = null; private Single(){} public static Single getInstance() //同步函数就没必要了,同步整个函数致使效率降低 { if(t==null)//解决效率问题 { synchronized(Single.class)//解决安全问题 { if(t==null) t = new Single(); } } return t; } }
所以说开发中还是应用饿汉式,但是在面试里考察懒汉式,因为其技术含量高
二、死锁示例
死锁是线程间相互等待锁锁造成的
死锁:常见就是,同步的嵌套
面试时,会让写死锁程序,只要写的出来,就说明死锁已经理解
- class Deadlock implements Runnable
- {
- private boolean flag;
- public Deadlock(boolean flag) {
- // TODO Auto-generated constructor stub
- this.flag = flag;
- }
- public void run()
- {
- if(flag)
- {
- while(true)
- synchronized (lock.A_LOCK) {
- System.out.println(“if…alock”);
- synchronized (lock.B_LOCK) {
- System.out.println(“if…block”);
- }
- }
- }
- else {
- while(true)
- synchronized (lock.B_LOCK) {
- System.out.println(“else…block”);
- synchronized (lock.A_LOCK) {
- System.out.println(“else…alock”);
- }
- }
- }
- }
- }
- class lock
- {
- public static final Object A_LOCK = new Object();
- public static final Object B_LOCK = new Object();
- }
- class Main
- {
- public static void main(String[] args)
- {
- Deadlock t1 = new Deadlock(true);
- Deadlock t2 = new Deadlock(false);
- Thread j1 = new Thread(t1);
- Thread j2 = new Thread(t2);
- j1.start(); j2.start();
- }
- }
class Deadlock implements Runnable { private boolean flag; public Deadlock(boolean flag) { // TODO Auto-generated constructor stub this.flag = flag; } public void run() { if(flag) { while(true) synchronized (lock.A_LOCK) { System.out.println("if...alock"); synchronized (lock.B_LOCK) { System.out.println("if...block"); } } } else { while(true) synchronized (lock.B_LOCK) { System.out.println("else...block"); synchronized (lock.A_LOCK) { System.out.println("else...alock"); } } } } } class lock { public static final Object A_LOCK = new Object(); public static final Object B_LOCK = new Object(); } class Main { public static void main(String[] args) { Deadlock t1 = new Deadlock(true); Deadlock t2 = new Deadlock(false); Thread j1 = new Thread(t1); Thread j2 = new Thread(t2); j1.start(); j2.start(); } }
if…alock else…block
锁上了,j1线程拿a锁,j2线程拿b锁,两者都在等待,但是不释放锁,就形成了死锁,致使程序死掉,在开发中发生死锁的概率非常低。因为在代码内某处,CPU肯定会切换另一线程,所以死锁的情况发生的概率极低,但是一旦发生,程序就会彻底卡壳
关于线程同步问题和锁的总结:
1、synchronized是为了保护多线程同时访问同一个资源时对资源内部成员的破坏。
2、线程同步方法(非同布)是通过锁来实现,每一个对象实例都有且仅有一个锁this,这个锁与一个特定的对象关联,某线程一旦获取了这个锁,那么其他访问该对象的线程就无法再访问该对象的其他同步方法。线程可以拥有多个锁
3、对于静态同步方法,锁是针对这个类的,锁对象是该类的字节码对象(class)。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。
4、对于同步,要时刻清醒在哪个对象上同步,这是关键。
5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析,并保证原子操作期间别的线程无法访问竞争资源。
6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞(死锁)。