首页 > 基础资料 博客日记
Java并发编程(1)
2025-09-14 11:30:02基础资料围观12次
Java资料网推荐Java并发编程(1)这篇文章给大家,欢迎收藏Java资料网享受知识的乐趣
基础
1、并行跟并发的区别
- 并行:同一时刻,多个线程都在执行,这就要求有多个CPU分别执行多个线程。
- 并发:在同一时刻,只有一个线程执行,但在一个时间段内,两个线程都执行了。其实现依赖于CPU切换线程,因为切换时间很短,所以基本对于用户是无感知的。
2、什么是进程和线程
- 进程:程序运行起来后在内存中执行,并附带有运行所需的资源,是系统进行资源分配的基本单位。
- 线程:CPU是被分配到线程的,所以线程是CPU分配的基本单位。在Java中,当我们启动一个main函数就相当于启动了一个JVM进程,而main函数的线程就是主线程。一个进程中有多个线程,多个线程共用进程的堆和方法区,但每个线程都有自己的程序计数器和栈。
3、线程有几种创建方式
- 继承Thread类:重写run方法,调用start()方法启动线程。
- 缺点:单继承,继承了Thread就不能继承别的类了
public static class MyThread extends Thread { @Override public void run() { System.out.println("this is child thread"); } } public static void main(String[] args){ MyThread thread = new MyThread(); thread.start(); }
- 实现Runnable接口:重写run()方法,这是一个任务,要包装成Thread才能start。
- 优点:只需要实现Runnable,业务逻辑和线程机制解耦。可以被多个线程复用。
- 缺点:也是用完就销毁。
public class RunnableTask extends Runnable { public void run() { System.out.println("Runnable!"); } } public static void main(String[] args){ RunnableTask task = new RunnableTask(); new Thread(task).start(); }
- 实现Callable接口:重写call()方法,通过FutureTask获取任务执行的返回值。
public class CallerTask implements Callable < String > { public String call () throws Exception { return "Hello,i am running!" ; } public static void main ( String [] args) { //创建异步任务 FutureTask < String > task = new FutureTask < String > ( new CallerTask ()); //启动线程 new Thread ( task ) .start(); try { //等 待 执 ⾏ 完 成 ,并获取返回结果 String result = task . get(); System.out.println ( result) ; } catch ( InterruptedException e ) { e.printStackTrace (); } catch ( ExecutionException e ) { e.printStackTrace (); } } }
4、为什么调用start()方法时会执行run()方法?那为什么不直接调用run()
- JVM执行start方法,会先创建一个线程,由创建出来的线程去执行run方法,才能起到多线程的效果。如果直接调用run方法,那么run还是运行在主线程中,相当于顺序执行。
5、线程有哪些常用的调度方法
6、线程有几种状态
状态 | 说明 |
NEW | 初始状态:线程被创建,还没调用start方法 |
RUNNABLE | 运行状态:就绪 + 运行 |
BLOCKED | 阻塞状态:阻塞于锁 |
WAITING | 等待状态:等待其他线程做出一定动作(通知或中断) |
TIME_WATING | 超时等待:指定时间自行返回 |
TERMINATED | 终止状态:已经执行完毕 |
- 初始状态:用new Thread()创建线程对象,还没调用start()时,此时只是被实例化。
- 就绪:线程已经具备运行条形,只差操作系统调度。
- 运行:当CPU把时间片分配给线程时,进入Running,执行run()方法里的代码。可能会发生:
- 执行完毕-->终止
- 调用yield()-->放弃CPU,回到就绪
- 被系统抢占调度-->回到就绪
- 进入阻塞或等待-->转到响应状态
- 阻塞:当线程尝试获取锁,但锁被其他线程占用,会进入阻塞状态。一旦获取锁,就进入running状态
- 等待:线程调用wait()、join()等时,会进入等待状态。必须由notify()或notifyAll()才能唤醒,回到runnable状态
- 超时等待:线程调用带超时参数的方法进入超时等待状态。到了超时时间或被notiry()唤醒后回到runnable
- 终止:执行完run()或抛出未捕获异常结束时,进入终止状态。
7、什么是线程上下文切换
CPU资源分配采用时间片轮转,也就是给每个线程分配一个时间片,线程在时间片内占用CPU执行任务。当线程使用完时间片后,就会处于就绪状态并让出CPU让其他线程用,这就是线程上下文切换。
8、守护线程了解吗
Java中的线程分为两类:daemon线程(守护线程)和user线程(用户线程)
在JVM启动时会调用main函数,其所在线程就是一个用户线程。JVM内部还启动了很多守护线程,如垃圾回收线程。
守护线程和用户线程的区别是,当最后一个非守护线程结束时,JVM会正常退出(此时不管当前是否存在守护线程)。
9、线程间有哪些通信方式
- volatile和synchronized关键字:
- volatile:保证变量在多线程间的可见性,不保存原子性。
- synchronized:保证同一时刻只有一个线程执行被保护的代码块,提供原子性和可见性。常用于操作共享变量、临界区的互斥访问。
- 等待/通知机制:线程调用wait()进入等待队列,释放锁;另一个线程在条件满足后调用notify或notifyAll唤醒。
- 管道输入/输出流:用于线程间直接传递数据。一个线程写入
PipedOutputStream
,另一个线程从PipedInputStream
读取。适合流式传输。 - 使用Thread.join():一个线程等待另一个线程执行完毕后再继续。常用于 主线程等待子线程结果 的场景。
- 使用ThreadLocal:为每个线程单独提供一个变量副本。线程间不共享数据,避免竞争和加锁。
文章来源:https://www.cnblogs.com/xiaoqian01/p/19083406
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
上一篇:剑指offer-27、字符串的排列
下一篇:没有了