欢迎大家来到IT世界,在知识的湖畔探索吧!
线程
- 线程(Thread)是一个程序内部一条执行路径
- 多线程指从硬件上实现执行多条流程的技术
线程创建
- 方式一:继承Thread类
① 编码简单
② 线程类已继承Thread类,无法再继承其他类,不便于扩展,线程有执行结果不可以直接返回
public class ThreadDemo { public static void main(String[] args) { // 创建线程对象 Thread t = new MyThread(); // 启动线程 t.start(); } } / * 定义线程类继承Thread,重写run方法 */ class MyThread extends Thread { @Override public void run() { System.out.println("线程执行"); } }
欢迎大家来到IT世界,在知识的湖畔探索吧!
- 方式二:实现Runnable接口(匿名内部类形式)
① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展
② 多一层对象包装,线程有执行结果不可以直接返回
欢迎大家来到IT世界,在知识的湖畔探索吧!public class ThreadDemo2 { public static void main(String[] args) { // 创建任务对象 Runnable target = new MyRunnable(); // 任务对象交给Thread Thread t = new Thread(target); // 启动线程 t.start(); // 匿名内部类实现方式-1 new Thread(new Runnable() { @Override public void run() { System.out.println("执行线程-匿名内部类1"); } }).start(); // 匿名内部类实现方式-2 new Thread(() -> { System.out.println("执行线程-匿名内部类2"); }).start(); } } / * 定义任务类,实现Runnable接口 */ class MyRunnable implements Runnable { / * 重写run方法 */ @Override public void run() { System.out.println("执行线程"); } }
- 方式三:实现Callable接口
① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展
② 可以在线程执行完成后获取结果
③ 编码稍微复杂
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class ThreadDemo3 { public static void main(String[] args) { // 创建任务对象 Callable
callable = new MyCallable(); // Callable任务对象交给FutureTask对象,该对象是Runnable的对象 FutureTask
f = new FutureTask<>(callable); // 给Thread线程处理 Thread t = new Thread(f); // 启动线程 t.start(); // 获取结果 try { String res = f.get(); System.out.println(res); } catch (Exception e) { e.printStackTrace(); } } } / * 定义任务类,实现Callable接口, 声明结果类型 */ class MyCallable implements Callable
{ / * 重写call方法 */ @Override public String call() throws Exception { return "执行线程"; } }
线程安全
- 多个线程同时写同一共享资源,可能会出现业务安全问题,称为线程安全
线程同步
- 解决线程安全问题
- 核心思想:加锁,对共享资源进行加锁,同时只能一个线程操作,完成后释放锁
- 锁对象唯一
① 使用共享资源作为锁对象
② 实例方法使用this作为锁对象
③ 静态方法使用类名.class作为锁对象
- 加锁方式
① 同步代码块,使用synchronized进行加锁,把出现线程安全问题的核心代码块加锁
② 同步方法,使用synchronized进行加锁,把出现线程安全问题的核心方法加锁
③ Lock锁
欢迎大家来到IT世界,在知识的湖畔探索吧!class SafeLock { public final Lock lock = new ReentrantLock(); public void draw() { // 加锁 lock.lock(); try { System.out.println("逻辑处理"); } finally { // 释放锁 lock.unlock(); } } }
线程池
- 可以复用线程的技术
- 解决不断创建新线程问题,提高效率
- 线程池实现API、参数说明
ThreadPoolExecutor构造器参数说明配图
欢迎大家来到IT世界,在知识的湖畔探索吧!
- 线程池处理Runnable任务
import java.util.concurrent.*; public class ThreadPoolDemo1 { public static void main(String[] args) { // 创建线程池对象 ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); // 任务对象 Runnable target = new MyRunnablePool(); // 线程池处理任务 pool.execute(target); } } / * Runnable任务 */ class MyRunnablePool implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+" 线程任务执行"); } }- 线程池处理Callable任务
欢迎大家来到IT世界,在知识的湖畔探索吧!import java.util.concurrent.*; public class ThreadPoolDemo2 { public static void main(String[] args) { // 创建线程池对象 ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); // 线程池处理任务 Future f = pool.submit(new MyCallablePool()); Future f1 = pool.submit(new MyCallablePool()); Future f2 = pool.submit(new MyCallablePool()); Future f3 = pool.submit(new MyCallablePool()); try { System.out.println(f.get()); System.out.println(f1.get()); System.out.println(f2.get()); System.out.println(f3.get()); } catch (Exception e) { e.printStackTrace(); } } } / * Runnable任务 */ class MyCallablePool implements Callable { @Override public String call() throws Exception { return Thread.currentThread().getName()+" 线程任务执行"; } } - Executors工具类线程池,大型并发系统可能出现系统风险,内存溢出
public class ThreadPoolDemo3 { public static void main(String[] args) { // 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。 ExecutorService pool = Executors.newFixedThreadPool(3); pool.execute(new MyRunnableExecutorPool()); // 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。 ExecutorService pool1 = Executors.newSingleThreadExecutor(); pool1.execute(new MyRunnableExecutorPool()); } } / * Runnable任务 */ class MyRunnableExecutorPool implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+" 线程任务执行"); } } - 创建线程池
① 方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
② 方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象
定时器
- 控制任务延时调用或周期调用的技术
- 定时器的方式
① 方式一:Timer定时器
-Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入
-可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行
② 方式二:ScheduledExecutorservice定时器
-基于线程池,某个任务的执行情况不会影响其他定时任务的执行
欢迎大家来到IT世界,在知识的湖畔探索吧!public class TImerDemo2 { public static void main(String[] args) { // 创建定时器对象 ScheduledExecutorService pool = Executors.newScheduledThreadPool(3); // 开启定时任务 pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() +"执行a"); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }, 0, 2, TimeUnit.SECONDS); pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() +"执行b"); } }, 0, 2, TimeUnit.SECONDS); } }
线程并发、并行
- 并发
① CPU同时处理线程的数量有限
② CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,感觉这些线程在同时执行,这就是并发
- 并行
① 在同一个时刻上,同时有多个线程在被CPU处理并执行
生命周期
- 线程状态,线程的状态:也就是线程从生到死的过程,以及中间经历的各种状态及状态转换
线程状态转换说明配图
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/88246.html