Java 线程与进程(1):基础知识及用法(问答形式)

1 Java 中有几种新起线程的方式?run和start的区别?

方式一:自定义线程继承Thread
方式二:实现Runnable接口

 public static void main(String[] args) {
 		// 方式一
        NewThread1 newThread1 = new NewThread1();
        newThread1.start();

		// 方式二
        NewThread2 newThread2 = new NewThread2();
        new Thread(newThread2).start();
    }

    public static class NewThread1 extends Thread{
        @Override
        public void run() {
            super.run();
            System.out.println("new thread by extends Thread");
        }
    }

    public static class NewThread2 implements Runnable{
        @Override
        public void run() {
            System.out.println("new thread by implements Runnable");
        }
    }

run是函数调用 和线程没有任何关系;
start会走底层,走系统层 最终调度到 run函数,这才是线程。

2 怎么让Java线程安全停止工作?

stop()还是interrupt()的选择:

  • stop() : 暴力方式,不要用(过时), 如下载一部分终止危险,且线程机制中有来不及释放的碎片
  • interrupt():协作方式,可以安全停止(以下有Thread和Runnable两种方式的中断处理代码)
public class EndThread {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();

        MyRunnable myRunnable = new MyRunnable();
        Thread runableThread = new Thread(myRunnable);

        Thread.sleep(1000);

        runableThread.interrupt();
        myThread.interrupt();// 发出中断信号 但不会自己使线程停止 需线程中通过isInterrupted()做判断处理
    }

    public static class MyThread extends Thread{
        @Override
        public void run() {
            super.run();
            String name = Thread.currentThread().getName();
            while (!isInterrupted()) {
                System.out.println(name + " ==== is run state" + isInterrupted());
            }
        }
    }

    public static class MyRunnable implements Runnable{
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            // 获取当前线程的中断信息状态
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println(name + " ==== is run state" + Thread.currentThread().isInterrupted());
            }
        }
    }
}

3 多线程中的并行和并发的理解

并行:类比几个车道就可以有几辆车并行行驶
并发:和时间有关系,计算吞吐量,类比车流量

4 线程常用的方法和线程状态(图),各个方法使用场景及流程

在这里插入图片描述
4.1 sleep与wait的区别
sleep 是休眠,等休眠时间一过,才有执行权的资格(无条件可以休眠)
wait 是等待,需要人家来唤醒,唤醒后,才有执行权的资格(某些原因与条件需要等待一下)
注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度

另外,sleep在 catch异常时会被 InterruptedException e 清除中断标记

4.2 如何控制线程的顺序——join控制

public class JoinThreadTest {
    public static void main(String[] args) throws InterruptedException{
        JoinThread joinThreadA = new JoinThread("A");
        JoinThread joinThreadB = new JoinThread("B");

        joinThreadA.start();
        //放弃当前线程的执行,并返回对应的线程的执行,  joinThreadA执行完了,main线程才有执行的机会
        joinThreadA.join();
        joinThreadB.start();
    }


    public static class JoinThread extends Thread{
        public JoinThread(String name){
            super(name);
        }
        @Override
        public void run() {
            super.run();
            for(int i=0;i<100;i++){
                System.out.println(this.getName() + ":" + i);
            }
        }
    }
}

4.3 如何让出当前线程执行权—yield(几乎不用)
用法与上面的 join 一样,只不过执行效果是等其他线程执行完了最后才执行设置 yield 的线程。

4.4 关于守护线程----场景?:

// 主线程执行完毕后守护线程也跟着一起结束
public class DaemonThread {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "---" + i);
                }
            }
        };
        t.setDaemon(true); // 设置了守护线程
        t.start(); // 谁调用的 main, main管了我 我就守护main

        // 主线程,是为了 等 Thread t 10秒钟
        Thread.sleep(10000);
        // 走到这里,代表主线程结束,主线程结束不管t线程有没有结束都必须结束,因为t线程是守护线程,守护了main
    }
}

5 对锁的使用和区分(类锁/对象锁/显示锁)—死锁

5.1 类锁------隐式锁

public class GPSEngine {
    private static GPSEngine gpsEngine;

    public GPSEngine getGpsEngine(){
        if (gpsEngine == null){
            gpsEngine = new GPSEngine();
        }
        return gpsEngine;
    }

    // 持有GPSEngine.class的类锁
    public static synchronized GPSEngine getGpsEngine1(){
        if (gpsEngine == null){
            // 其他任何线程不能进来,效率低
            gpsEngine = new GPSEngine();
        }
        return gpsEngine;
    }

    // 标准单例模式------DCL
    public static synchronized GPSEngine getInstance(){
        if (gpsEngine == null){
            // 持有类锁
            synchronized (GPSEngine.class){
                if (gpsEngine == null){
                    gpsEngine = new GPSEngine();
                }
            }
        }
        return gpsEngine;
    }
}

5.2 对象锁------隐式锁

public class SynTest {
	private long count =0;
	private Object obj = new Object(); // 作为一个锁 对象锁obj

	public long getCount() {
		return count;
	}

	public void setCount(long count) {
		this.count = count;
	}

	public void incCount(){
		synchronized (obj){ // 使用一把锁------对象锁
			count++;
		}
	}

	// synchronized == 类锁
	public synchronized void incCount2(){
			count++;
	}
	
	// this == 类锁
	public void incCount3(){
		synchronized (this){
			count++;
		}
	}

	// 线程
	private static class Count extends Thread{
		private SynTest simplOper;

		public Count(SynTest simplOper) {
			this.simplOper = simplOper;
		}

		@Override
		public void run() {
			for(int i=0;i<10000;i++){
				simplOper.incCount(); // count = count+10000
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		SynTest simplOper = new SynTest();

		// 启动两个线程
		Count count1 = new Count(simplOper);
		Count count2 = new Count(simplOper);
		count1.start();
		count2.start();

		Thread.sleep(50);
		System.out.println(simplOper.count);//20000
	}
}

5.3 显示锁 Lock/ReentrantLock

// 声明一个显示锁之可重入锁  new 可重入锁------ 非公平锁
	private Lock lock = new ReentrantLock();
	
	public void incr(){
		// 使用 显示锁 的规范
		lock.lock();
		try{
			count++;
		} finally {   // 打死都要执行  最后一定会执行
			lock.unlock();
		}
	}

	// 可重入锁 意思就是递归调用自己,锁可以释放出来
	// synchronized == 天生就是 可重入锁
	// 如果是非重入锁 ,就会自己把自己锁死
	public synchronized void incr2(){
		count++;
		incr2();
	}

6 生产者消费者案例(产生问题—解决方案)

6.1 初始版代码

public class CommunicationDemo {
    public static void main(String[] args) {
        // 创建资源对象
        Res res = new Res();
        // 创建生产者任务
        ProduceRunnable produceRunnable = new ProduceRunnable(res);
        // 创建消费者任务
        ConsumeRunnable consumeRunnable = new ConsumeRunnable(res);
        // 启动生产者任务
        new Thread(produceRunnable).start();
        // 启动消费者任务
        new Thread(consumeRunnable).start();
    }
}

// 生产者任务
class ProduceRunnable implements Runnable {
    private Res res;

    ProduceRunnable(Res res) {
        this.res = res;
    }

    @Override
    public void run() {//执行线程任务
        for (int i = 0; i < 20; i++) {
            res.put("面包🍞");
        }
    }
}

// 消费者任务
class ConsumeRunnable implements Runnable {
    private Res res;

    ConsumeRunnable(Res res) {
        this.res = res;
    }

    @Override
    public void run() {//执行线程任务
        for (int i = 0; i < 20; i++) {
            res.out();
        }
    }
}

class Res {
    private String name;
    private int id;

    public void put(String name) { // 生产一个面包
        id += 1;
        this.name = name + " 商品编号:" + id;
        System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name);
    }

    public void out() {// 消费
        id -= 1;
        System.out.println(Thread.currentThread().getName() +  ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name);
    }
}

6.2 内置锁解决安全问题------先全部生产再消费

// 对操作共享数据的地方加入同步锁的方式来解决安全问题
    public synchronized void put(String name) {
        id += 1;
        System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.id);
    }

    public synchronized void out() {
        System.out.println(Thread.currentThread().getName() +  ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.id);
        id -= 1;
    }

6.3 实现生产一个消费一个------ wait/notify等待唤醒机制

class Res2 {
    private String name;
    private int id;
    private boolean flag; // 定义标记 默认第一次为false

    public synchronized void put(String name) { // 生产一个面包
        if (!flag) {
            id += 1;
            System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.id);
            flag = true;// 修改标记

           //唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的
            notify(); // 注意:⚠️ wait();  notify();  这些必须要有同步锁包裹着

            //当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了
            try {
                wait();  // 生产好一个,休息下
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void out() {// 消费
         // 消费之前判断标记
        if (flag) {
            System.out.println(Thread.currentThread().getName() +  ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.id);
            flag = false;//修改标记
            notify();
            try {

                wait(); // 消费完休息下
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

7 ThreadLocal——隔离线程(待完善)

设置的值只对当前设置的线程有用,类似于副本,不会全局修改,Handler中有用到
ThreadLocalMap: 性能最高

8 并发基础补充知识点(待完善)

8.1 线程的生命周期

8.2 第三种创建方式的实质

8.3 死锁的条件及解决方案

8.4 活锁

9 CAS(Compare And Swap)

9.1 CAS含义及原理
原子操作:全部完成或全部未做,不可再分,如synchronized
含义:比较并交换
原理:循环指令直到成功

9.2 悲观锁和乐观锁
悲观锁:上下文切换 一次切换3-5ms 效率低
乐观锁:一次指令0.6ns

9.3 CAS问题
ABA问题:期间被换了但保持原样(本质已变)——加个版本戳解决
开销问题
只能保证一个共享变量的原子操作

9.4 原子操作类的使用(凡是以Atomic开头的)
更新基本类型类
更新数组类
更新引用类型

10 队列和阻塞队列

10.1 含义
队列:先进先出
阻塞队列:BlockingQueue接口

10.2 常见阻塞队列
有界
ArrayBlockingQueue:
LinkedBlockingQueue:

无界
PriorityBlockingQueue:
DelayBlockingQueue:
LinkedTranceferQueue:

其他
SychrononsQueue:不存储元素的阻塞队列
LinkedBlockingDeque:

11 线程池

11.1 什么是线程池?为什么要用线程池?

缩短任务的总执行时间

11.2 ThreadPoolExcutor 线程池
各个参数的含义
corePoolSize:核心线程数
maxnumPoolSize:最大线程数
keepAliveTime:空闲线程存活时间
unit:存活时间单位
workQueue:阻塞队列
threadFactory:
handler:拒绝策略,四种

拒绝策略名称说明
DiscardOldestPolicy排在最前面最老的的丢弃
CallerRunsPolicy你行你来做,谁往线程池提交任务谁来做
DiscardPolicy最新提交的任务直接丢弃
AbortPolicy抛出异常,默认策略

流程:
核心线程==》阻塞队列==》最大线程数==》拒绝策略

提交任务
submit

关闭线程池
shutdown:中断未在执行的线程
shutdownNow:尝试关闭所有线程,但不一定会成功

11.3 合理配置线程池
任务特性
CPU密集型:CPU在不断计算的——配置线程数不能超过CPU核心数
Runtime.getRuntime().availableProcessors()
IO密集型:与网络进行通讯,有读写磁盘操作的——机器CPU核心数*2
混合型:

12 面试题汇总

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了python应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值