并发编程面试题0

并发编程

1、并行和并发有什么区别?

并行和并发都是指多个任务同时执行的概念,但是它们之间有着明显的区别
并行:多个任务在同一时间同时执行,通常需要使用多个处理器或者多核处理器来实现。例如,一个多核CPU的计算机同时执行多个进程或多个线程是,就是采用并行的方式来处理任务的,这样能提高计算机的处理效率。

并发:多个任务同时进行,但是这些任务的执行是交替进行的,即一个任务执行一段时间后,再执行另一个任务。它是通过操作系统的协作调度来实现各个任务的切换,达到看上去同时进行的效果。例如一个多线程程序中的多个线程就是同时运行的,但是因为一个CPU只能处理一个线程,所以在任意时刻只有一个线程在执行,线程之间会通过竞争的方式来获取CPU的时间片。

在这里插入图片描述

2、线程有几种创建方式

在Java中,线程的创建主要有以下4种方式:
1、继承Thread类
通过继承Thread类并重写其run()方法,可以创建一个新的线程。然后,可以创建这个类的实例并调用其start()方法来启动线程。

public class Test3 {
    public static void main(String[] args) {
        // 创建实例。
        MyThread myThread = new MyThread();
        // 设置线程的name
        myThread.setName("myThread");
        // 调用start()方法来启动线程
        myThread.start();
        
        // 获取主线程的name
        System.out.println(Thread.currentThread().getName());
    }


}

// 1、通过继承Threadl类创建线程
class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的代码,获取线程的name
        System.out.println(Thread.currentThread().getName());
    }
}

2、实现Runnable接口
通过实现Runnable接口并重写其run()方法,可以创建一个任务对象。然后,可以创建Thread类的实例并将任务对象作为参数传递给其构造函数,最后调用start()方法来启动线程。这种方式允许你继承其他类,因为Java不支持多重继承。

public class Test3 {
    public static void main(String[] args) {
        // 创建任务对象。
        MyThread2 myThread2 = new MyThread2();
        // 创建Thread类的实例并将任务对象作为参数传递给其构造函数
        Thread thread = new Thread(myThread2);
        // 设置线程的name
        thread.setName("myThread2");
        // 调用start()方法来启动线程
        thread.start();
        
        // 获取主线程的name
        System.out.println(Thread.currentThread().getName());
    }


}

// 2、通过实现Runnable接口来创建线程
class MyThread2 implements Runnable {
    @Override
    public void run() {
        // 线程执行的代码
        System.out.println(Thread.currentThread().getName());
    }
}

3、实现Callable接口

Callable接口类似于Runnable,但允许线程执行的任务有返回值,并且可以抛出异常。Future接口表示异步计算的结果;·可以使用ExecutorService来提交Callable任务,并使用返回的Future对象来检索结果或检查任务是否完成。

public class Test3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1、通过FutureTask启动线程
        FutureTask<String> futureTask = new FutureTask<>(new MyThread3());
        Thread thread = new Thread(futureTask);
        thread.setName("myThread3");
        thread.start();
        // 等待任务完成并获取结果
        System.out.println(futureTask.get());

        // 2、通过ExecutorService启动线程
        // 创建一个ExecutorService
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // 提交Callable任务,并获取Future对象
        Future<String> future = executorService.submit(new MyThread3());

        // 等待任务完成并获取结果
        System.out.println(future.get());

        // 关闭ExecutorService
        executorService.shutdown();
    }


}

// 3、通过实现Callable接口来创建线程
class MyThread3 implements Callable<String> {

    @Override
    public String call() throws Exception {

        return Thread.currentThread().getName();
    }
}

4、使用线程池

尽管线程池本身不是直接创建线程的方式,但它是一种管理线程的高效方式。你可以使用ExecutorService框架(如Executors类提供的静态工厂方法)来创建和管理线程池。线程池中的线程可以被重复利用,以执行多个任务,从而减少了线程创建和销毁的开销。

3、Java线程启动为什么是调用start()方法而不是直接调用run()方法?

JVM执行start()方法,会先创建一个线程并使其经历其生命周期的各个阶段(例如,新建、就绪、运行、阻塞、死亡等),当新线程被启动后,它会自动调用run()方法,这才会起到多线程的效果;如果直接调用run()方法,就相当于调用了一个普通方法,程序中依然只有主线程这一个线程。

通过调用start()方法启动新线程,可以实现并发执行多个任务,提高程序的效率。如果我们直接调用run()方法,那么这些任务将只能在主线程中顺序执行,无法实现并发。但是,一个线程的start()方法不能被重复调用,而run()方法可以

4、线程有哪些常用的调度方法

1、设置线程优先级:
Java中的线程优先级通过整数表示,范围从1到10。可以使用Thread类的setPriority()方法来设置线程的优先级。更高优先级的线程倾向于比低优先级的线程更早地执行,但线程优先级并不保证绝对的执行顺序,而是提供了一个提示,让调度器更可能将CPU时间分配给优先级较高的线程

2、线程调度相关的线程状态转换方法:
thread.start(): 启动一个新线程,使其进入就绪状态。调用此方法后,线程将自动调用其run()方法。

thread.sleep(long millis): 休眠,使当前线程(即调用该方法的线程)暂停执行一段时间(以毫秒为单位),当休眠结束后,线程自动转为就绪状态

thread.yield(): 让步,暂停当前正在执行的线程对象,并执行其他线程。但具体哪个线程将恢复执行取决于操作系统的线程调度算法。

thread.join(): 等待,等待该线程终止。调用某线程的join()方法将使得当前线程暂停执行,直到目标线程执行完毕

object.wait(): 等待,Object类中的wait()方法,使当前线程(即调用该方法的线程)等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。

object.wait(long): 等待,相比wait()方法多了一个超时参数,如果线程调用这个方法,没有在指定时间内被其他线程唤醒,那么这个方法会因超时而返回。

thread.interrupt(): 中断线程。如果线程在等待、睡眠或进行某些阻塞操作,则interrupt()方法会将其唤醒并抛出InterruptedException。

thread.isInterrupted()

thread.interrupted()

3、线程等待和通知:
object.notify(): 通知,唤醒在此对象监视器上等待的单个线程选择是任意性的

object.notifyAll(): 通知,唤醒在此对象监视器上等待的所有线程

public class Test4 {
    public static void main(String[] args) throws Exception {

        Object lock = new Object();

        Thread thread1 = new Thread(() -> {
            try {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + "线程进入永久等待" + LocalTime.now());
                    // 使线程进入等待,直到被唤醒
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + "线程永久等待被唤醒" + LocalTime.now());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }, "thread1");

        Thread thread2 = new Thread(() -> {
            try {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + "线程进入永久等待" + LocalTime.now());
                    // 使线程进入等待,直到被唤醒,没有被唤醒则等待3s
                    lock.wait(3000);
                    System.out.println(Thread.currentThread().getName() + "线程永久等待被唤醒" + LocalTime.now());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }, "thread2");

        // 启动线程
        thread1.start();
        thread2.start();

        // 休眠1s,让thread1先执行
        Thread.sleep(1000);
        synchronized (lock) {
            // 随机唤醒在此对象监视器上的一个线程
            lock.notify();
            // 唤醒在此对象监视器上的所有线程
//            lock.notifyAll();
        }
        // 使主线程暂停执行,直到thread1线程执行完毕。
        thread1.join();
        thread2.join();

    }
}
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenzm666666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值