java线程池的操作(基础)
Callable 接口
相对于Callable接口 ,Runnable接口是没有是没有参数和返回值的异步方法,Callable与Runnable类似,但是有返回值。它是一个参数化的类型,只有一个方法call。
//接口定义
// Callable接口
public interface Callable<V> {
V call() throws Exception;
}
//Runnable接口
public interface Runnable {
public abstract void run();
}
//1. 编写类实现Callable接口 , 实现call方法 class XXX implements Callable<T> {
@Override
public <T> call() throws Exception {
return T; }
}
//2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
Callable<Integer> callable=new Callable();
FutureTask<Integer> future = new FutureTask<>(callable);
// 3. 通过Thread,启动线程
new Thread(future).start();//Runnable
Integer i=future.get();// Future
FutureTask包装器可将Callable转换成Future和Runnable,同时实现两者的接口。
在对get的调用时,主线程的就会阻塞,直到获得结果为止,继续执行
Synchronized锁的用法
1、同步代码块:
synchronized (对象){
// 需要被同步的代码;
}
2、synchronized还可以放在方法声明中,表示整个方法为同步方法。
例如:
public synchronized void show (String name){
….
}
synchronized的锁是什么?
任意对象都可以作为同步锁,所有对象都自动含有单一的锁(监视器)
同步方法的锁: 静态方法(类名.class)、非静态方法(this)
同步代码块: 自己指定,很多时候也是指定为this或类名.class
注意:
必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全
一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方法共用同一把锁(this),同步代码块(指定需谨慎)
同步的范围
如何找问题,即代码是否存在线程安全?(非常重要)
明确哪些代码是多线程运行的代码
明确多个线程是否有共享数据
明确多线程运行代码中是否有多条语句操作共享数据
如何解决呢?(非常重要)
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
即所有操作共享数据的这些语句都要放在同步范围中
注意:
范围太小: 没锁住所有有安全问题的代码
范围太大: 没发挥多线程的功能。
释放锁的操作
当前线程的同步方法、同步代码块执行结束。
当前线程在同步代码块、同步方法中遇到 break、return 终止了该代码块、该方法的继续执行。
当前线程在同步代码块、同步方法中出现了未处理的 Error 或 Exception,导致异常结束。
当前线程在同步代码块、同步方法中执行了线程对象的 wait() 方法,当前线程暂停,并释放锁。
synchronized 与 Lock 锁有何区别
Lock 是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized 是隐式锁,出了作用域自动释放
Lock 只有代码块锁,synchronized 有代码块锁和方法锁
使用 Lock 锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用顺序:
Lock →同步代码块(已经进入了方法体,分配了相应资源) → 同步方法(在方法体之外)
wait() 与 notify() 和 notifyAll()
wait(): 令当前线程挂起并放弃 CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用 notify()或notifyAll() 方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行。
notify(): 唤醒正在排队等待同步资源的线程中优先级最高者结束等待
notifyAll (): 唤醒正在排队等待资源的所有线程结束等待.
————————————————
版权声明:本文为CSDN博主「ABin-阿斌」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Mango_Bin/article/details/115859092
Java中的四种线程池 . ExecutorService
线程池创建的目的是为了增加的系统的效率,如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程 就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容 器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
-缓存线程池
会返回一个带缓存的线程池,该池在必要时会创建线程,在线程空闲60秒后终止线程
/**
缓存线程池. (长度无限制) 执行流程:
1. 判断线程池是否存在空闲线程
2. 存在则使用
3. 不存在,则创建线程 并放入线程池, 然后使用
* * * * * * */
ExecutorService service = Executors.newCachedThreadPool(); //向线程池中 加入 新的任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
-定长线程池
该线程池的线程数由参数决定
/**
* 定长线程池.
* (长度是指定的数值) * 执行流程:
* * 1. 判断线程池是否存在空闲线程
* 2. 存在则使用
* 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
* 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程 */
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
我们开启了三个线程,但线程池中只能放两个线程,所以第三个线程只能等待,线程池中出现空闲线程才能执行
-单线程线程池
返回一个执行器,在一个单一线程中执行各个任务
//效果与定长线程池 创建时传入数值1 效果一致.
/**
单线程线程池. 执行流程:
1. 判断线程池 的那个线程 是否空闲
2. 空闲则使用
4. 不空闲,则等待 池中的单个线程空闲后 使用
* * * * * */
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName()); }
});
-周期性任务定长线程池
public static void main(String[] args) {
/**
* 周期任务 定长线程池.
* 执行流程:
* 1. 判断线程池是否存在空闲线程
* 2. 存在则使用
* 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
* 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程 *
* 周期性任务执行时:
* 定时执行, 当某个时机触发时, 自动执行某任务 .
*/
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 定时执行 * 参数1. * 参数2. * 参数3. */
//runnable类型的任务 时长数字 时长数字的单位
/*service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("俩人相视一笑~ 嘿嘿嘿"); }
},5,TimeUnit.SECONDS);
*/
/**
* 周期执行
* * * * */
/*
参数1. runnable类型的任务
参数2. 时长数字(延迟执行的时长)
参数3. 周期时长(每次执行的间隔时间)
参数4. 时长数字的单位
*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("俩人相视一笑~ 嘿嘿嘿"); }
},5,2,TimeUnit.SECONDS);
}