java中的线程(二)
单例模式的3中实现方法
第一种(懒汉式)
public class SingletonDemo1 {
private static SingletonDemo1 instance=null;
private SingletonDemo1() { //构造方法私有
}
public static SingletonDemo1 getInstance() {
if(instance==null) {
instance=new SingletonDemo1();
}
return instance;
}
}
这种方式线程不安全,我们在用的时候可以加锁
public class SingletonDemo1 {
private static SingletonDemo1 instance=null;
private SingletonDemo1() { //构造方法私有
}
public static synchronized SingletonDemo1 getInstance() {
if(instance==null) {
instance=new SingletonDemo1();
}
return instance;
}
}
使用:
SingletonDemo1 instance=SingletonDemo1.getInstance();
第二种(饿汉式)
public class SingletonDemo2 {
private static SingletonDemo2 instance=new SingletonDemo2();
private Signel2() {
}
public static SingletonDemo2 getInstance() {
return instance;
}
}
使用:
SingletonDemo2 istance=SingletonDemo2.getInstance;
第三种(枚举)
public enum SigletonDemo3 {
INSTANCE;
}
使用:
SigletonDemo3 instance=SigletonDemo3.INSTANCE;
生产者消费者模式
理解:有一个容器,生产者生产某个东西放在这个容器中,消费者消费这个东西。
为什么要使用生产者消费者模式:在线程开发中,生产者
就是生产数据的线程,消费者
就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。如果消费者的处理能力大于生产者,那么消费者就必须等待生产者,于是就引入了生产者消费者模式。
使用wait()与notifyAll()实现
假设生产者生产汉堡包,消费者消费汉堡包,在柜台上最多放下10个汉堡
汉堡类:
public class Hamburger {
private String name;
private int id;
private static AtomicInteger i = new AtomicInteger(0);
public Hamburger(String name) {
this.name = name;
id = i.incrementAndGet();
}
@Override
public String toString() {
return "Hamburger [name=" + name + ", id=" + id + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return this.id;
}
}
柜台:
public class Counter {
// 用队列存储商品
Deque<Hamburger> queue = new LinkedList<Hamburger>();
private static int MAX_VALUE = 10; // 能存储的最大数量
public synchronized void produce() throws Exception {
while (queue.size() >= MAX_VALUE) {
System.out.println("汉堡的数量已经足够多了,生产者停止生产汉堡,等待消费者消费汉堡");
wait();
}
Hamburger h = new Hamburger("鸡腿堡");
queue.offer(h);
System.out.println("生产者产量了一个汉堡:" + h.getName() + "一共有汉堡数" + queue.size());
notifyAll();
}
public synchronized void consume() throws Exception {
while (queue.size() <= 0) {
System.out.println("已经没有汉堡了,消费者停止消费,等待生产者生产");
wait();
}
Hamburger h = queue.poll();
System.out.println("消费者消费了一个汉堡:" + h.getName() + "剩余:" + queue.size());
notifyAll();
}
}
生产者的线程:
public class Producer implements Runnable {
private Counter counter;
public Producer(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
while (true) {
try {
counter.produce();
Thread.sleep(200);
} catch (Exception e) {
e.getStackTrace();
}
}
}
}
消费者的线程:
public class Consumer implements Runnable {
private Counter counter;
public Consumer(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
while (true) {
try {
counter.consume();
Thread.sleep(300);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
测试:
public class Test {
public static void main(String[] args) {
Counter counter=new Counter();
Thread p1=new Thread(new Producer(counter));
Thread p2=new Thread(new Producer(counter));
Thread p3=new Thread(new Producer(counter));
Thread c1=new Thread(new Consumer(counter));
Thread c2=new Thread(new Consumer(counter));
Thread c3=new Thread(new Consumer(counter));
Thread c4=new Thread(new Consumer(counter));
p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
c3.start();
c4.start();
}
}
结果的部分截图:
线程池
线程池的好处:
- 提高响应速度
- 提高线程的可管理性
- 防止服务器过载
- 降低资源销毁
线程池的一个构造方法
参数理解:
corePoolSize
:线程池中的核心线程数量,在没有用的时候也不会被收回.
maximumPoolSize
:线程池中可以容纳的最大线程数量
keepAliveTime
:线程池中的除了核心线程之外的其他的最长可以保留的时间,也就是非核心线程可以保留的最长的空闲时间
unit
:计算时间的一个单位
workQueue
:等待队列
handler
:拒绝策略
执行
拒接策略
AbortPolicy
:不执行新任务,直接抛出异常,提示线程池已满,默认该方式。
CallerRunsPolicy
:直接调用execute来执行当前任务。
DiscardPolicy
:丢弃任务,但是不抛出异常。
DiscardOldestPolicy
:抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。先从任务队列中弹出最先加入的任务,空出一个位置,然后再次执行execute方法把任务加入队列
线程池的创建
newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程
创建:
运行结果:
newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
创建:
结果:
newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数。
创建:
运行:
newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行
创建:
运行:
提交方式
execute:
- execute只能提交Runnable类型的任务,无返回值。
- execute在执行任务时,如果遇到异常会直接抛出
submit
-submit既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。
-submit不会直接抛出,只有在使用Future的get方法获取返回值时,才会抛出异常