Java单例模式的学习总结

Java实现单例模式的几种方式:

  • 1.单例模式的概念:
  • 2.如何实现单例模式
  • 3.Synchronized的使用
    • 3.1修饰一个代码块

1.单例模式的概念:

参考网址:http://www.importnew.com/21866.html
https://blog.csdn.net/u014672511/article/details/79774847
http://www.importnew.com/18872.html
http://www.importnew.com/18872.html
单例模式是指在应用整个生命周期内只能存在一个实例。它能够避免对象的重复创建,减少创建实例的系统开销,节省内存。

2.如何实现单例模式

我这里重点讲的是使用java中的Synchronized。

synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。

synchronized是Java中的关键字,是一种同步锁
1.无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
2.每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
3.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。


3.Synchronized的使用

3.1修饰一个代码块

知识点重点:
        每个对象只有一个锁(lock),而synchronized只锁定对象,所以在多线程编程的时候,我们要让每个线程访问的不是同一个对象,不然的话就会出现线程阻塞的情况,只有当Thred1执行完后,Thread2才会去执行

例子:

/**
 * 同步线程
 */
class SyncThread implements Runnable {
   //static声明的变量会放到方法区内存里面,只会保存一份不会被重复创建
   private static int count;
 
   public SyncThread() {
      count = 0;
   }
 
   public  void run() {
      synchronized(this) {
         for (int i = 0; i < 5; i++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }
 
   public int getCount() {
      return count;
   }
}

新建一个类Thread_tongbu.java用来做测试,放入以下代码:

public class Thread_tongbu {
    public static void main(String[] args) {
        SyncThread syncThread = new SyncThread();
        Thread thread1 = new Thread(syncThread, "SyncThread1");
        Thread thread2 = new Thread(syncThread, "SyncThread2");
        thread1.start();
        thread2.start();
    }
}

结果如下:

SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

Process finished with exit code 0

这里我们会发现线程2被阻塞了,等到线程1执行完才执行。
因为在执行synchornized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的。

要解决上诉问题,我们必须要让线程执行的不是同一个对象,因为每个对象只有一个锁,谁拿到谁用,所以我们可以对代码做以下修改:

Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
thread1.start();
thread2.start();

结果:

SyncThread1:0
SyncThread2:1
SyncThread1:2
SyncThread2:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread1:7
SyncThread1:8
SyncThread2:9

不是说一个线程执行synchronized代码块时其它的线程受阻塞吗?为什么上面的例子中thread1和thread2同时在执行。这是因为synchronized只锁定对象,每个对象只有一个锁(lock)与之相关联,而上面的代码等同于下面这段代码:

SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();

这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。

你可能感兴趣的:(Java学习总结)