好,接着来看一下线程问题,
创建线程的三种方式:
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
```
与Runnable的区别,1)有返回结果,2)可以抛出检查异常
具体用代码来实现下:
线程池:
创建有限的线程资源为更多的任务提供服务。享元模式。
// java中对线程池的抽象:ExecutorService 创建一个固定大小的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(2);
/*for (int i = 0; i < 10; i++) {
threadPool.submit(()->{
System.out.println(Thread.currentThread().getName()+"任务执行");
});
}*/
// 执行带有返回结果的任务
Future future = threadPool.submit(() -> {
System.out.println(Thread.currentThread().getName()+"执行计算...");
Thread.sleep(1000);
return 10;
});
System.out.println(future.get());
threadPool.shutdown(); // 不接收新任务,当所有任务运行结束,整个线程池关闭
corePoolSize 核心线程数目 (最多保留的线程数)
5
maximumPoolSize
10
workQueue 阻塞队列 如果任务超过了核心线程数,进入队列进行排队,直到有空闲的线程
10
如果任务过多,阻塞队列都放不下了,还会创建新的线程来救急
corePoolSize+救急的线程 <= maximumPoolSize(最大线程数)
21 会抛出拒绝提交任务异常
keepAliveTime 生存时间- 针对救急线程
60
unit 时间单位 秒
// 创建固定大小的线程池
Executors.newFixedThreadPool(2);
核心线程数=最大线程数(没有救急线程被创建)
阻塞队列 无界,可以放任意数量的任务,
适合执行数量有限,长时间运行的任务
// 创建缓冲线程池
Executors.newCachedThreadPool()
核心线程数是0, 最大线程数是Integer的最大值(救急线程可以无限创建)
生存时间是60s
适合任务数比较密集,但每个任务执行时间较短的情况
// 创建单线程线程池
Executors.newSingleThreadExecutor()
使用场景:希望多个任务排队执行
区别:
Executors.newSingleThreadExecutor() 线程个数始终为1,不能修改
Executors.newFixedThreadPool(1) 初始时为1,以后还可以修改
// 带有日程安排功能的线程池
```java
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
// 让任务推迟一段时间执行
// 参数1.任务对象, 参数2,3 推迟的时间
/*service.schedule(()->{
System.out.println("执行任务...");
}, 10L, TimeUnit.SECONDS);*/
// 以一定的频率反复执行任务(任务不会重叠)
// 参数1,任务对象, 参数2,初始推迟时间, 参数3,4 时间间隔和单位
/*service.scheduleAtFixedRate(()->{
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello");
}, 0, 1, TimeUnit.SECONDS);*/
// delay表示从上一个任务结束,到下一个任务开始之间的时间
service.scheduleWithFixedDelay(()->{
System.out.println("hello");
}, 0, 1, TimeUnit.SECONDS);
// service.shutdown();
```
### 3. 原子操作类
AtomicInteger
AtomicBoolean
...
```java
// 创建原子整数类
private static AtomicInteger i = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
i.getAndIncrement(); // 获取并且自增 i++
// i.incrementAndGet(); // 自增并且获取 ++i
}
});
Thread t2 = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
i.getAndDecrement(); // 获取并且自减 i--
}
});
t1.start();
### 4. 线程安全集合类
StringBuffer 线程安全
String 不可变类 , 都是线程安全的
Random 线程安全
Vector 实现了List,并且线程安全
Hashtable 实现了Map,并且线程安全
5.0新增的线程安全集合类
ConcurrentHashMap 实现了Map,并且线程安全
ConcurrentSkipListMap 实现了Map(可排序),并且线程安全
CopyOnWriteArrayList 实现了List,并且线程安全


BlockingQueue 阻塞队列
队列 FIFO , first in first out
Queue --> LinkedList
```java
private static BlockingQueue<Product> queue = new ArrayBlockingQueue<>(5);
public static void main(String[] args) {
// 生产者线程
new Thread(()->{
for (int i = 0; i < 10; i++) {
Product p = new Product(i);
System.out.println(Thread.currentThread().getName()+"生产了:"+p);
try {
queue.put(p);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// 消费者线程
for (int j = 0; j < 5; j++) {
new Thread(()->{
for (int i = 0; i < 2; i++) {
try {
Product p = queue.take();
System.out.println(Thread.currentThread().getName()+"消费了:"+p);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
```
### 5. ThreadLocal
```java
// 线程局部变量
private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal() {
@Override // 初始值
protected Object initialValue() {
return new SimpleDateFormat("yyyy-MM-dd"); // 存入当前线程
}
};
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
SimpleDateFormat sdf = local.get(); // 获取本线程自己的局部变量
Date date = sdf.parse("1951-10-09"); // 每个线程使用的是自己的SimpleDateFormat因此没有争用
System.out.println(Thread.currentThread().getName() + " " + date);
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}
/*for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("1951-10-09");
System.out.println(Thread.currentThread().getName() + " " + date);
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}*/
```
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
```