首页 > 基础资料 博客日记

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、线程有哪些常用的调度方法

image

 

6、线程有几种状态

状态 说明
NEW 初始状态:线程被创建,还没调用start方法
RUNNABLE 运行状态:就绪 + 运行
BLOCKED 阻塞状态:阻塞于锁
WAITING 等待状态:等待其他线程做出一定动作(通知或中断)
TIME_WATING 超时等待:指定时间自行返回
TERMINATED 终止状态:已经执行完毕

image

  • 初始状态:用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进行投诉反馈,一经查实,立即删除!

标签:

上一篇:剑指offer-27、字符串的排列
下一篇:没有了

相关文章

本站推荐

标签云