线程使用的优化
原因
1、一个线程大致需要1MB的内存空间,如果线程无法回收,那么会导致程序出现内存溢出异常
2、如果线程可以被回收,大量的回收线程会导致系统的负担较大,导致降低程序的执行效率
解决方案:线程池
简介:
多个线程的容器,可以用来管理其中的线程
优点:
1、可以设定线程的上限
2、会复用线程,在线程池中挑选一个暂时没有执行任务的线程对象,使用该对象执行新任务
3、避免频繁的创建与销毁线程
4、无须操心线程的创建与销毁,只需给其添加所需执行的任务
线程池的体系结构
Executor(接口)
方法:void executor(Runnable command);执行任务
子类或子接口
ExecutorService(接口)
方法:
void shutdown();关闭线程池
Future<?> sumbit(Runnable task);给线程池提交要执行的任务
子类:
ThreadPoolExecutor(类)
注意:该类创建时需要传入多个对象,导致创建难度较大
子类:
ScheduledThreadPoolExecutor(l类)
Executors工具类
作用:帮你创建线程池
常用方法:
1、创建一个固定长度的线程池,该线程池中线程数量恒定
public static ExecutorService newFixedThreadPool(int nThreads)
参数:线程池中的线程数量
2、创建一个缓存线程池,该线程池中的线程数量由任务数量决定
public static ExecutorService newCachedThreadPool()
该线程池中闲置的线程会在60秒后被回收,如果闲置线程在60秒内,有任务需要执行,就直接使用该线程
3、创建一个单例线程池,该线程池中只有一条线程
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
4、创建一个抢占线程池,jdk1.8提供(了解)
public static ExecutorService newWorkStealingPool()
1、该线程池中的任务不按顺序执行
2、该线程池中含有窃取算法
3、适合于超级耗时的任务
4、该线程池中所有线程都是守护线程
5、创建一个调度线程池,该线程池中线程数量恒定(掌握)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
参数:线程池中线程数量
6、创建一个单例调度线程池,该线程池中只有一条线程(了解)
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
调度线程池特有的方法ScheduledThreadPoolExecutor
延迟执行:
延迟后重复调用:
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
参数:
command:要执行的任务
initialDelay:延迟时间
period:重复执行的间隔时间
计算规则:前一次任务开始时间与本次任务开始时间的间隔
如果前一次任务执行时间<间隔时间,延迟间隔时间-前一次任务执行时间后执行本次任务
如果前一次任务执行时间>=间隔时间,那么当前一次任务执行完毕后,直接执行本次任务
unit:时间单位
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
参数:
command:要执行的任务
initialDelay:延迟时间
delay:重复执行的间隔时间
计算规则:前一次任务结束时间与本次任务开始时间的间隔
unit:时间单位
Callable接口
简介
作用:回调,当任务执行完毕后,可以使用其对象在其他线程中获取其返回值
使用
1、与线程结合使用
步骤:
1、创建Callable接口对象
2、使用FutureTask包裹Callable接口对象
3、创建线程对象传入FutureTask对象
4、启动线程
5、使用FutureTask对象获取结果
2、与线程池结合使用
步骤:
1、创建Callable接口对象
2、创建线程池对象
3、使用线程池对象调用submit方法传图其Callable对象
4、使用submit方法返回值,调用get方法获取任务结果
Callable与Runnable的区别
1、Callable接口中call方法有返回值,Runnable接口中run方法没有返回值
2、Callable接口中call方法有异常声明,Runnable接口中run方法没有异常声明
3、Callable接口对象不能直接配合Thread对象使用,Runnable接口对象可以直接与Thread对象配合使用
练习:同时拼接an,mz,最终拼接两个结果并输出
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
*练习:同时拼接a~n,m~z,最终拼接两个结果并输出
*a~n:97~110
*m~z:109~122
*/
public class Test {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
AddCallable callable01 = new AddCallable(97, 110);
AddCallable callable02 = new AddCallable(109, 122);
Future<String> submit01 = service.submit(callable01);
Future<String> submit02 = service.submit(callable02);
service.shutdown();
try {
String string01 = submit01.get();
String string02 = submit02.get();
System.out.println(string01+string02);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class AddCallable implements Callable<String>{
private int start;
private int end;
public AddCallable(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public String call() throws Exception {
StringBuffer buffer = new StringBuffer();
for (int i = start; i <= end; i++) {
char c = (char) i;
buffer.append(c+"");
}
return buffer.toString();
}
}
锁
锁的体系结构
Lock(接口)
方法:
lock():关闭锁
unlock():打开锁
子类:
ReentrantLock:重写锁
ReentrantLock(接口)
方法:
writeLock():获取写的锁对象
readLock():获取读的锁对象
子类:
ReentrantReadWriteLock:读写锁
该类中提供了两个对象
WriteLock对象,写锁
ReadLock对象,读锁
这两个类又实现了Lock接口
特性:
写——写:同步
读——写:同步
读——读:异步
作业1:使用线程池完成生产者与消费者模式
作业2:使用线程池与Callable接口完成10的阶乘结果+1~50和的结果。(10的阶乘:10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test02 {
public static void main(String[] args) {
SumCallable01 sumCallable01 = new SumCallable01(1, 50);
SumCallable02 sumCallable02 = new SumCallable02(1, 10);
ExecutorService service = Executors.newFixedThreadPool(2);
Future<Integer> submit01 = service.submit(sumCallable01);
Future<Integer> submit02 = service.submit(sumCallable02);
try {
Integer integer01 = submit01.get();
Integer integer02 = submit02.get();
System.out.println("1~50的和为:"+integer01);
System.out.println("10的阶乘为:"+integer02);
System.out.println("10的阶乘+1~50和的结果为"+(integer01+integer02));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//计算1~50的和
class SumCallable01 implements Callable<Integer>{
private int start;
private int end;
public SumCallable01(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
int sum01 = 0;
int sum02 = 1;
for (int i = start; i <= end; i++) {
sum01 += i;
}
return sum01;
}
}
//计算10的阶乘
class SumCallable02 implements Callable<Integer>{
private int start;
private int end;
public SumCallable02(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
int sum02 = 1;
for (int i = start; i <= end; i++) {
sum02 = sum02 * i;
}
return sum02;
}
}