多线程编程案例

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把当前线程都保存起来,方便管理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值