线程组ThreadGroup
- 一个线程的集合,线程组中包含很多个线程,每一个线程默认的线程组名称:main
- 线程组还可以包括其他线程组。 线程组形成一个树,除了初始线程组之外,每个线程组都有一个父进程。
- 允许线程访问有关其线程组的信息,但不能访问有关其线程组的父线程组或任何其他线程组的信息。
构造方法
//源码
public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
}
常用方法
- public final ThreadGroup getThreadGroup():获取当前线程所属的线程组
- public final String getName() :获取线程组名称
线程池
线程出现的问题
- 线程是宝贵的内存资源,单个线程占1MB空间,过多分配易造成内存溢出
- 频繁的创建及销毁线程会增加虚拟机回收频率、资源开销、造成程序性能下降
- 因此线程池出现了
线程池的概念
- 线程容器,可设定线程分配的数量上限
- 将预先创建的线程对象存入池中,并重用线程池中的线程对象
- 避免频繁的创建和销毁
线程池的原理
获取线程池
创建线程池
public class TestThreadPool {
public static void main(String[] args) {
// 1. 创建固定线程个数的线程池对象
//线程池里可存在4个线程
ExecutorService es = Executors.newFixedThreadPool(4);
// 2. 创建任务
Runnable runnable = new Runnable() {
private int ticket = 100;
@Override
public void run() {
while (true) {
if(ticket <= 0) {
break;
}
System.out.println(Thread.currentThread().getName() + "买了" + ticket--);
}
}
};
// 3. 提交任务
for(int i = 0; i < 5; i++) {
es.submit(runnable);
}
// 4. 关闭线程池
es.shutdown();
}
}
执行结果
注
// 1. 创建单线程的线程池
ExecutorService es = Executors.newSingleThreadExecutor();
// 1. 创建缓冲线程池,线程的个数由任务来决定
ExecutorService es = Executors.newCachedThreadPool();
Callable接口
public interface Callable<V>{
public V call() throws Exception;
}
- JDK5加入,与Runnable接口类似,实现之后代表一个线程任务
- Callable具有泛型返回值、可以声明异常
Future接口
- 概念:异步接受ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值
- 方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
示例
- 使用Future和Callable接口
- 使用两个线程,并发计算1-50,51-100的和,再进行汇总
//示例
public class TestCallable {
public static void main(String[] args) throws Exception {
// 1.创建线程池对象
ExecutorService es = Executors.newFixedThreadPool(2);
// 2. 提交任务并得到Future对象,任务有Callable匿名对象来承担
Future<Integer> future1 = es.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
//完成1-50的加和运算并得到结果
System.out.println("start 1-50 count...");
int sum = 0;
for(int i = 1; i <= 50; i++) {
sum += i;
}
return sum;
}
});
Future<Integer> future2 = es.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
//完成51-100的加和运算并得到结果
System.out.println("start 51 - 100 count...");
int sum = 0;
for(int i = 51; i <= 100; i++) {
sum += i;
}
return sum;
}
});
// 3. 使用Future对象的get()方法得到运算结果
System.out.println("1-100的加和结果为:" + (future1.get() + future2.get()));
// 4. 关闭资源
es.shutdown();
}
}
结果
Lock接口
- JDK5加入,与synchronized比较,显示定义,结构更灵活
- 提供更多实用性方法,功能更加强大,性能更优越
常用方法
//获取锁,如锁被占用,则等待
void lock()
//尝试获取锁(成功true,失败false,不阻塞)
boolean tryLock
//释放锁
void unlock()
//示例
public class TestLock implements Runnable {
Lock l = new ReentrantLock();
private int ticket = 100;
@Override
public void run() {
while (true) {
l.lock();
try {
if(ticket <= 0) {
break;
}
System.out.println(Thread.currentThread().getName() + " sells " + ticket--);
} catch (Exception e) {
e.printStackTrace();
}finally {
l.unlock();
}
}
}
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(4);
for(int i = 0; i < 4; i++) {
es.submit(new TestLock());
}
es.shutdown();
}
}
执行结果
杂
线程安全的集合
Collections中的工具方法
Queue接口(队列)
//示例
public class TestQueue {
public static void main(String[] args) {
// 1. 创建PriorityQueue队列对象
PriorityQueue<String> q = new PriorityQueue<String>();
// 2. 队列添加元素,“入列”
q.offer("a");
q.offer("b");
q.offer("c");
q.offer("d");
q.offer("e");
// 3. 取值,“出列”
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
}
}
执行结果
定时器工具:java.util.Timer
- 可以重复执行某个任务/或者执行一次任务
构造方法
- public Timer():构造一个新的计时器
TimerTask
- 由定时器Timer来安排是执行一次/重复执行当前任务
- public abstract void run():任务要执行的操作
成员方法:
//终止定时器
public void cancel()
//在指定日期时间内容将执行这个 任务!
public void schedule(TimerTask task,Date time)
//在指定时间后执行当前这个task任务
public void schedule(TimerTask task, long delay)
//在某个时间内容执行这个任务,然后每经过period时间毫秒值后重复执行任务!
public void schedule(TimerTask task, long delay,long period)
示例
public class TimerDemo {
public static void main(String[] args) {
//创建一个定时器
Timer timer = new Timer() ;
// public void schedule(TimerTask task, long delay)
// timer.schedule(new MyTask(), 3000);
//开启定时任务的同时,时间到了,取消定时器
//timer.schedule(new MyTask(timer), 3000);
// public void schedule(TimerTask task, long delay,long period)
timer.schedule(new MyTask(), 2000, 3000);
}
}
//自定义一个类:继承自TimerTask:定时任务
class MyTask extends TimerTask{
//在成员位置声明一个定时器类型变量
private Timer t ;
public MyTask() {
}
public MyTask(Timer t) {
this.t = t ;
}
@Override
public void run() {
System.out.println("bom...爆炸了...");
//取消定时器
//t.cancel();
}
}
示例,在某个时间,删除指定文件
public class Demo05 {
public static void main(String[] args) throws ParseException {
String source = "2020-11-2 19:56:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(source);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
File file = new File("C:\\Users\\demo");
File[] files = file.listFiles();
for (File f : files) {
System.out.println("删除了"+f.getName()+"文件");
f.delete();
}
}
}, date);
}
}