线程创建
① 编码简单
② 线程类已继承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("线程执行"); }}
① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展
② 多一层对象包装,线程有执行结果不可以直接返回
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("执行线程"); }}
① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展
② 可以在线程执行完成后获取结果
③ 编码稍微复杂
import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;public class ThreadDemo3 { public static void main(String[] args) { // 创建任务对象 Callable<String> callable = new MyCallable(); // Callable任务对象交给FutureTask对象,该对象是Runnable的对象 FutureTask<String> 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<String> { /** * 重写call方法 */ @Override public String call() throws Exception { return "执行线程"; }}
线程安全
线程同步
① 使用共享资源作为锁对象
② 实例方法使用this作为锁对象
③ 静态方法使用类名.class作为锁对象
① 同步代码块,使用synchronized进行加锁,把出现线程安全问题的核心代码块加锁
② 同步方法,使用synchronized进行加锁,把出现线程安全问题的核心方法加锁
③ Lock锁
class SafeLock { public final Lock lock = new ReentrantLock(); public void draw() { // 加锁 lock.lock(); try { System.out.println("逻辑处理"); } finally { // 释放锁 lock.unlock(); } }}
线程池
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()+" 线程任务执行"); }}
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<String> f = pool.submit(new MyCallablePool()); Future<String> f1 = pool.submit(new MyCallablePool()); Future<String> f2 = pool.submit(new MyCallablePool()); Future<String> 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<String> { @Override public String call() throws Exception { return Thread.currentThread().getName()+" 线程任务执行"; }}
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定时器
-基于线程池,某个任务的执行情况不会影响其他定时任务的执行
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处理并执行
生命周期