1.单例模式
(1)饿汉 类加载的时候,就创建实例(线程安全)
//饿汉模式
class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
(2)懒汉 第一次调用getInstance方法创建实例(线程不安全)
//懒汉模式
//单线程版
class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//多线程版
class Singleton {
private static Singleton instance = null;
private Singleton() {}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//二次判断高性能的多线程版
class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
保证线程安全的操作:1..加锁if判定 和new操作 2..双重if判定 3..volatile关键字
2.阻塞队列
特殊的队列(线程安全)——如果队列满 再入队列就会阻塞, 如果队列空 再出队列就会阻塞。
应用于生产者消费者模型
BlockingQueue
LinkedBlockingQueue 他俩入队列出队列的方法是 put()和take()
生产者消费者模型得先实现一个队列 有两种方法:
(1)基于链表 (2)基于数组(环形队列)


3.定时器
作用:定时器就是一个闹钟,给定时器一个任务规定XXX事件后执行。
接口:schedule,把一个任务+时间加入到定时器中
结构:
a)Task类,用来描述一个任务
b)带优先级的阻塞队列
c)线程,扫描队首元素
d)mailBox防止扫描线程忙等
mport java.util.concurrent.PriorityBlockingQueue;
public class Timer {
private static class TimerTask implements Comparable<TimerTask> {
private Runnable command;
private long time;
//具体的任务实例
private TimerTask(Runnable command, long after) {
//Runnable实例表示任务具体是什么
this.command = command;
//时间戳
this.time = System.currentTimeMillis() + after;
}
private void run() {
command.run();
}
//重写比较方法返回要等待的时间
@Override
public int compareTo(TimerTask o) {
return (int)(time - o.time);
}
}
//带优先级的阻塞队列 用来组织若干个task(任务),哪个任务时间到了就先执行,快要到时间的任务优先级更高
private PriorityBlockingQueue<TimerTask> queue = new PriorityBlockingQueue<>
();
//用来防止扫面线程忙等
private Object mailbox = new Object();
//此线程用来扫面队首元素,看队首元素是否已经到规定的执行时间,时间到了就执行,不到就再把它放回队列继续等待。
//因为Timer的构造方法中构造了Worker类 并且调用了它的start()方法 它也在创建Timer对象时就执行run();
private class Worker extends Thread {
@Override
//扫面队首元素,看队首元素是否已经到规定的执行时间,时间到了就执行,不到就再把它放回队列继续等待。
public void run() {
while (true) {
try {
TimerTask task = queue.take();
long ms = System.currentTimeMillis();
if (task.time > ms) {
queue.put(task);
synchronized (mailbox) {
mailbox.wait(task.time - ms);
}
} else {
task.run();
}
} catch (InterruptedException e) {
break;
}
}
}
}
//Timer的构造方法
public Timer() {
Worker worker = new Worker();
worker.start();
}
//安排一个任务给定时器,指定时间后执行这个任务
public void schedule(Runnable command, long after) {
TimerTask task = new TimerTask(command, after);
queue.offer(task);
//唤醒扫描 看新放进去的任务 和 别的任务比较谁先执行
synchronized (mailbox) {
mailbox.notify();
}
}
public static void main(String[] args) throws InterruptedException {
Timer timer = new Timer();
//一个任务
Runnable command = new Runnable() {
@Override
public void run() {
System.out.println("我来了");
timer.schedule(this, 1000);
}
};
timer.schedule(command, 3 * 1000);
}
}
4.线程池(为了解决线程的创建销毁开销)
线程池:就是提前把一些线程创建好放进池子里,用的时候从池子里取,用完了也不用销毁线程,而是又放回池子里(用户态完成)。
主要矛盾:用户可能很多(进程很多),工作人员比较少(内核里执行任务的东西比较少)
线程池内部结构:
(1)描述一个任务(使用Runnable即可,只需要知道 任务做什么)
(2)组织很多队列(使用阻塞队列来保存当前所有任务)
(3)有一些线程,来负责执行阻塞队列中的任务。让这些线程从阻塞队列中取任务并执行。如阻塞队列为空,就等待。
(4)还需要一个List把当前线程都保存起来,方便管理。
10万+

被折叠的 条评论
为什么被折叠?



