首先要明白什么是单例模式,简单来说假如有类 A, 当我们 new 一个 A 的对象的时候,如果是单例模式,先判断是否已经有这个对象了,如果有就返回,没有再创建。这相当于将一个对象和一个类绑定了,该怎么做呢?我们知道,在Java中,如果将一个属性或方法声明为 static 的,那么这个属性或方法就是属于这个类的了,与类绑定了。那办法就呼之欲出了,我们在类中声明一个自身的对象,声明为static的,同时不允许做出修改,加上final关键字。
除此之外,单例模式有两种实现方式,即 饿汉模式 与 懒汉模式。饿汉模式是在类加载的时候直接创建对象,懒汉模式就是当第一次 new 类 A 的对象的时候,才去创建唯一实例。
从以上的描述不难看出,如果是饿汉模式,我们直接将属性初始化即可,如果是懒汉模式,就需要在构造函数中检查是否已经存在相应的对象了,因为要保证单例,当已经存在的时候就不能够再创建了。除此之外,无论是单例还是多例,都需要为外界提供一个 getInstance 函数来获得对象。
饿汉模式
public class Singleton{
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
懒汉模式(方式一)
public class Singleton{
private static final Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
this.instance = new Singleton();
}
return instance;
}
}
懒汉模式(方式二:双重校验)
public class Singleton{
private static final Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
this.instance = new Singleton();
}
}
}
return instance;
}
}
这个问题考察的是线程之间的通信,线程之间通信的手段可以通过系统提供的线程间通信方法配合锁、信号量等方法实现,方法很多,会两到三个即可。
方法一:synchronized关键字+wait()+notifyAll()
public class PrintNumber{
private int num;
private static final Object lock = new Object();
public void print(int order){
while(true){
synchronized(lock){
if(num >= 10){break;}
while(num % 3 == order){
try{
System.out.println(Thread.currentThread().getName()+num);
num++;
lock.notifyAll();
lock.wait();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
public static void main(String[]args){
PrintNumber test = new PrintNumber();
Thread t0 = new Thread(()->{test.print(0);},"A");
Thread t1 = new Thread(()->{test.print(1);},"B");
Thread t2 = new Thread(()->{test.print(2);},"C");
t0.start();
t1.start();
t2.start();
}
}
方法二:RentrantLock
import java.util.concurrent.locks.ReentrantLock;
public class Main{
private static int num;
private ReentrantLock lock = new ReentrantLock();
public void print(int order){
while (true){
lock.lock();
if(num >= 40){
break;
}
if(num % 3 == order){
System.out.println(Thread.currentThread().getName()+num);
num++;
}
lock.unlock();
}
}
public static void main(String[]args){
Main test = new Main();
Thread t0 = new Thread(()->{test.print(0);},"A");
Thread t1 = new Thread(()->{test.print(1);},"B");
Thread t2 = new Thread(()->{test.print(2);},"C");
t0.start();
t1.start();
t2.start();
}
}
方法三:Semaphore信号量
定义 Runnable 线程
import java.util.Date;
/**
* 这是一个简单的Runnable类,需要大约5秒钟来执行其任务。
* @author shuang.kou
*/
public class MyRunnable implements Runnable {
private String command;
public MyRunnable(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Time = " + new Date());
processCommand();
System.out.println(Thread.currentThread().getName() + " End. Time = " + new Date());
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
定义线程池
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
private static final Long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
//使用阿里巴巴推荐的创建线程池的方式
//通过ThreadPoolExecutor构造函数自定义参数创建
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 10; i++) {
//创建WorkerThread对象(WorkerThread类实现了Runnable 接口)
Runnable worker = new MyRunnable("" + i);
//执行Runnable
executor.execute(worker);
}
//终止线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
}
}