一.启动线程的方式
1.自定义类继承Thread类并重写run方法,然后创建该类的对象调用start方法。
格式:
Thread t1 = new SubThreadRun(); // 声明Thread类型的引用指向子类类型的对象(创建自定义类
SubThreadRun 实现Thread接口)
t1.start();
2.自定义类实现Runnable接口并重写run方法,创建该类的对象作为实参来构造Thread 类型的对象,然后使用Thread类型的对象调用start方法。
格式:
TestRunnableRun srr = new TestRunnableRun (); // 自定义类TestRunnableRun实现Runnable接口类的run方法。
Thread t1 = new Thread(srr);
t1.start();
3. 实现 Callable 接口,使用 FutureTask 类创建线程
|
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class ThreadCallableTest implements Callable { @Override public Object call() throws Exception { // 计算 ~ 10000之间的累加和并打印返回 int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } System.out.println("计算的累加和是:" + sum); // 50005000 return sum; } public static void main(String[] args) { ThreadCallableTest tct = new ThreadCallableTest(); FutureTask ft = new FutureTask(tct); Thread t1 = new Thread(ft); t1.start(); Object obj = null; try { obj = ft.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("线程处理方法的返回值是:" + obj); // 50005000 } } |
4.通过创建线程池启动线程
格式:
// 1.创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 2.向线程池中布置任务(自定义类实现Callable,重写接口中的call()方法,然后实例化类作为参数向线程池中布置任务 )
executorService.submit(new ThreadCallableTest());
// 3.关闭线程池
executorService.shutdown();
二.线程的生命周期

1.新建状态 - 使用new关键字创建之后进入的状态,此时线程并没有开始执行。
2.就绪状态 - 调用start方法后进入的状态,此时线程还是没有开始执行。
3.运行状态 - 使用线程调度器调用该线程后进入的状态,此时线程开始执行,当线程的时间片执行完毕后任务没有完成时回到就绪状态。
4.消亡状态 - 当线程的任务执行完成后进入的状态,此时线程已经终止。
5.阻塞状态 - 当线程执行的过程中发生了阻塞事件进入的状态,如:sleep方法。阻塞状态解除后进入就绪状态。
三.线程同步机制
1.基本概念
当多个线程同时访问同一种共享资源时,可能会造成数据的覆盖等不一致性问题,此时就需要对线 程之间进行通信和协调,该机制就叫做线程的同步机制。 多个线程并发读写同一个临界资源时会发生线程并发安全问题。
异步操作:多线程并发的操作,各自独立运行。
同步操作:多线程串行的操作,先后执行的顺序。
2.解决方案
由程序结果可知:当两个线程同时对同一个账户进行取款时,导致最终的账户余额不合理。 引发原因:线程一执行取款时还没来得及将取款后的余额写入后台,线程二就已经开始取款。 解决方案:让线程一执行完毕取款操作后,再让线程二执行即可,将线程的并发操作改为串行操 作。 经验分享:在以后的开发尽量减少串行操作的范围,从而提高效率。
3.实现方式
在Java语言中使用synchronized关键字来实现同步/对象锁机制从而保证线程执行的原子性,具体 方式如下: 使用同步代码块的方式实现部分代码的锁定,格式如下: synchronized(类类型的引用) { 编写所有需要锁定的代码; } 使用同步方法的方式实现所有代码的锁定。 直接使用synchronized关键字来修饰整个方法即可 该方式等价于: synchronized(this) { 整个方法体的代码 }
4.静态方法的锁定
当我们对一个静态方法加锁,如: public synchronized static void xxx(){….} 那么该方法锁的对象是类对象。每个类都有唯一的一个类对象。获取类对象的方式:类名.class。 静态方法与非静态方法同时使用了synchronized后它们之间是非互斥关系的。
5.注意事项
使用synchronized保证线程同步应当注意: 多个需要同步的线程在访问同步块时,看到的应该是同一个锁对象引用。 在使用同步块时应当尽量减少同步范围以提高并发的执行效率。
四.线程池
什么是线程池?
线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时.会提交到线程池的任务队列,处理完之后线程不会被销毁,而是仍然在线程池中等待下一个任务。
为什么要使用线程池?
因为java中创建一个线程,需要调用操作系统内核的API,操作系统要为线程分配一系列的资源,成本高,所以线程是一个重量级的对象,应该避免频繁创建和销毁。使用线程池就能很好地避免频繁创建和销毁。
本文详细介绍了Java中线程的基本概念,包括线程的启动方式、生命周期、同步机制及线程池的使用。通过具体示例展示了如何创建线程、解决线程间的竞争条件,并探讨了线程池的优势。
11万+

被折叠的 条评论
为什么被折叠?



