Java线程及其多线程入门

本文深入探讨Java多线程核心技术,包括Thread类与Runnable接口的使用、线程池原理及实现、线程安全问题的解决方案,以及JDK1.5中新特性Lock接口的应用。

Java多线程

_01Thread类及Runnable接口

线程执行具有随机性。


* 创建新执行线程的两种方法:
    1. 将类声明为 Thread 的子类。该类应重写 Thread 类的 run()方法。创建对象,开启线程。run方法相当于其他线程的main方法。
    2. 声明一个实现 Runnable 接口的类。实现 run()方法,然后创建Runnable 的子类对象,并传到某个线程的构造方法中,开启线程。
1、实现线程程序继承Thread

Thread是程序中的执行线程。JAVA虚拟机允许程序并发地运行多个执行线程。


例:继承Thread

/*
 * 定义Thread子类,重写run()方法
 */
public class SubThread extends Thread{
    public void run(){
        for (int i = 0; i < 5; i++){
            System.out.println("run..."+i);
        }
    }

    @Test
    /*
     * 创建和启动一个线程
     *      创建Thread子类对象
     *      子类对象调用方法start():
     *          让线程程序执行,JVM调用线程中的run
     */
    public void testSubThread(){
        SubThread st0 = new SubThread();
        SubThread st1 = new SubThread();
        st0.start();
        st1.start();
        for(int i = 0; i < 50; i++) {
            System.out.println(i);
        }
    }
2、为什么要继承Thread类
1*、:我们为什么要继承Thread类,并调用其的start方法才能开启线程呢?
     继承Thread类:因为Thread类用来描述线程,具备线程应该有功能。那为什么不直接创建Thread类的对象呢?
     如下代码:
     Thread t1 = new Thread();
     t1.run();//这样做没有错,但是该start调用的是Thread类中的run方法
              //而这个run方法没有做什么事情,更重要的是这个run方法中并没有定义我们需要让线程执行的代码。

2*、: 创建线程的目的是什么?
    是为了建立程序单独的执行路径,让多部分代码实现同时执行。也就是说线程创建并执行需要给定线程要执行的任务。
     对于之前所讲的主线程,它的任务定义在main函数中。自定义线程需要执行的任务都定义在run方法中。

3*、:多线程执行时,到底在内存中是如何运行的呢?
    多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。
    当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

3、获取线程名字Thread类方法
  1. 获取线程名字Thread类方法getName
public class NameThread extends Thread {
    public void run(){
        System.out.println(getName());
    }
}
    @Test
    /*
     * 每个线程,都有自己的名字
     * 新建的线程的默认名字为"Thread-0","Thread-1",...
     */
    public void testThreadName(){
        NameThread nt = new NameThread();
        nt.start();
    }
  1. 获取线程名字Thread类方法currentThread
    @Test
    /*
     * Thread中
     *      static Thread currentThread()返回正在执行的线程对象
     */
    public void testCurrentThread(){
        System.out.println(Thread.currentThread());
    }

4、线程名字设置
  1. 通过调用父类Thread的构造器
public class NameThread extends Thread {
    public NameThread(){
        super("小猫");
    }
    public void run(){
        System.out.println(getName());
    }
}
  1. 通过调用setName()方法设置
    public void testThreadName(){
        NameThread nt = new NameThread();
        nt.setName("��");
        nt.start();
    }

5、Thread类方法sleep
    @Test
    public void testSleepThread() throws Exception{
        SleepThread st = new SleepThread();
        st.start();
        for (int i = 0; i < 5; i++) {
            //睡眠500ms,500ms已到并且cpu切换到该线程继续向下执行
            Thread.sleep(500);
            System.out.println(i);
        }
    }

6、实现线程的另一种方式实现Runnable接口
/*
 * 实现线程的另一方式,接口实现
 * 实现接口Runnable,重写run方法
 */
public class SubRunnable implements Runnable{
    public void run(){
        for (int i = 0; i < 50; i++) {
            System.out.println("run..."+i);
        }
    }
}
    @Test
    /*
     * 实现接口方式的线程
     *      创建Thread类对象,构造方法中,传递Runnable接口实现类
     *      调用Thread类方法start()
     */
    public void testRunnable(){
        SubRunnable sr = new SubRunnable();
        Thread t= new Thread(sr);
        t.start();
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread()+"..."+i);
        }
    }

7、实现接口方式的好处
* 实现接口方式的好处:
     第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。
     实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。
    继承Thread类,线程对象和线程任务耦合在一起。
    一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。
    实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。
    (降低紧密性或者依赖性,创建线程和执行任务不绑定)

8、匿名内部类实现线程程序
public class NiMing {
    public static void main(String[] args) {
        new Thread(){
            public void run(){
                System.out.println("继承方式");
            }
        }.start();

        new Thread(new Runnable(){
            public void run(){
                System.out.println("实现接口方式");
            }
        }).start();
    }
}

_02 线程池

1、线程池原理
  1.在java中,如果每个请求到达就创建一个新线程,开销是相当大的。
  2.在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。
  3.除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。
    如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。
    为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。
  线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。
2、JDK5实现线程池
    /*
     * JDK1.5新特性,实现线程池程序
     * 使用工厂类 Executors中的静态方法创建线程对象,指定线程的个数
     *       static ExecutorService newFixedThreadPool(int 个数) 
     *      返回的是ExecutorService接口的实现类 (线程池对象)
     * 接口实现类对象,调用方法submit (Ruunable r) 提交线程执行任务
     */
    @Test
    public void testThreadPool(){
        //调用工厂类的静态方法,创建线程池对象
        //返回线程池对象,是返回的接口
        ExecutorService es = Executors.newFixedThreadPool(2);
        //调用接口实现类对象es中的方法submit提交线程任务
        //将Runnable接口实现类对象传递给submit
        es.submit(new ThreadPoolRunnable());
        es.submit(new ThreadPoolRunnable());
        es.submit(new ThreadPoolRunnable());
    }

public class ThreadPoolRunnable implements Runnable {
    public void run(){
        System.out.println(Thread.currentThread().getName()+"线程提交任务");
    }
}

3、实现线程的Callable接口方式
    /*
     * 实现线程池的Callable接口方式
     * 实现步骤:
     *      工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象
     *      返回线程池对象ExecutorService接口类型,调用submit提交进程任务
     *      submit(Callable c)
     */
    @Test
    public void testThreadPool1() throws InterruptedException, ExecutionException{
        ExecutorService es = Executors.newFixedThreadPool(2);
        //提交线程任务的方法submit方法返回 Future接口的实现类
        Future<String> f = es.submit(new ThreadPoolCallable());
        String s = f.get();
        System.out.println(s);
    }

public class ThreadPoolCallable implements Callable<String>{
    public String call(){
        return "Callable方式可以具有返回值";
    }
}

4、线程实现异步计算案例
 *:同步代码块的执行原理
     同步代码块: 在代码块声明上 加上synchronized
        synchronized (锁对象) {
        可能会产生线程安全问题的代码
    }
    同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
public class ThreadPoolCallable implements Callable<String>{
    public String call(){
        return "Callable方式可以具有返回值";
    }
}

    /*
     * 使用多线程技术,求和
     * 两个线程,一个计算1+100,另一个计算1+200的和
     * 两个线程的异步计算
     */
    @Test
    public void testThreadPoolAdd() throws InterruptedException, ExecutionException{
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Integer> f1 = es.submit(new GetSumCallable(100));
        Future<Integer> f2 = es.submit(new GetSumCallable(200));
        System.out.println(f1.get());
        System.out.println(f2.get());
        es.shutdown();
    }

_03 线程安全

*A:线程操作共享数据的安全问题
    如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。
    程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
1、同步代码块解决线程安全问题
public class TestTickets {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);

        t0.start();
        t1.start();
        t2.start();
    }
}
/*
 * 通过线程休眠,出现安全问题
 * 解决安全问题,Java程序,提供技术,同步技术
 * 公式:
 *      synchronized(任意对象){
 *          线程要操作的共享数据
 *      }
 *      同步代码块
 */
public class Tickets implements Runnable{
    private int ticket = 100;
    private Object obj = new Object();

    public void run(){
        while(true){
            //线程共享块,保证安全,加入同步代码块
            synchronized (obj) {
                if(ticket > 0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"出售的第"+ticket--);
                }
            }
        }
    }
}

2、同步的上厕所原理
a:不使用同步:线程在执行的过程中会被打扰
     线程比喻成人
     线程执行代码就是上一个厕所
     第一个人正在上厕所,上到一半,被另外一个人拉出来
b:使用同步:
    线程比喻成人
    线程执行代码就是上一个厕所
    锁比喻成厕所门
  第一个人上厕所,会锁门
  第二个人上厕所,看到门锁上了,等待第一个人上完再去上厕所
3、同步方法
  *  采用同步方法形式,解决线程的安全问题
  *  好处: 代码简洁
  *  将线程共享数据,和同步,抽取到一个方法中
  *  在方法的声明上,加入同步关键字
  *  
  *  问题:
  *    同步方法有锁吗,肯定有,同步方法中的对象锁,是本类对象引用 this
  *    如果方法是静态的呢,同步有锁吗,绝对不是this
  *    锁是本类自己.class 属性
  *    静态方法,同步锁,是本类类名.class属性

例:

public class Tickets implements Runnable{
    private int ticket = 100;

    public void run() {
        while (true) {
            payTicket();
        }
    }

    public synchronized void payTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "出售的第" + ticket--);
        }
    }
}

_04JDK1.5新特性Lock接口

*A:JDK1.5新特性Lock接口
    * Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
    * Lock接口中的常用方法
        void lock()
        void unlock()
    * Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能。
    * 我们使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,

1、例:对电影院卖票案例中Ticket
public class Tickets implements Runnable{
    //定义出售的资源
    private int ticket = 100;
    //在类的成员位置,创建Lock接口的实现类
    private Lock lock = new ReentrantLock();

    public void run(){
        while(true){
            //调用Lock接口方法lock获取锁
            lock.lock();
            //对票数贩毒案,大于0,可以出售,
            if(ticket > 0){
                try{
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
                }catch(Exception e){

                }finally{
                    //释放锁,调用Lock接口方法unlock
                    lock.unlock();
                }
            }
        }
    }
}
2、线程的死锁代码实现
public class LockA {
    private LockA(){}
    public static final LockA locka = new LockA();
}

public class LockB {
    private LockB(){}
    public static final LockB lockb = new LockB();
}

public class DeadLock implements Runnable{
    private int i = 0;
    public void run(){
        while(true){
            if(i % 2 == 0){
                //先进入A同步,在进入B同步
                synchronized (LockA.locka) {
                    System.out.println("if...locka");
                    synchronized (LockB.lockb) {
                        System.out.println("if...lockb");
                    }
                }
            }else{
                //先进入B同步,再进入A同步
                synchronized (LockB.lockb) {
                    System.out.println("else...lockb");
                    synchronized (LockA.locka) {
                        System.out.println("else...locka");
                    }
                }
            }
            i++;
        }
    }
}

public class DeadLockDemo {
    public static void main(String[] args) {        
        DeadLock dead = new DeadLock();
        Thread t0 = new Thread(dead);
        Thread t1 = new Thread(dead);
        t0.start();
        t1.start();
    }
}
3、线程等待与唤醒案例
*A:线程等待与唤醒案例介绍 
    等待唤醒机制所涉及到的方法:
       wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
       notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
       notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
   其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。

例:


资源类编写:

/*
 * 定义资源类,有2个成员变量
 * name,sex
 * 同时有2个线程,对资源中的变量操作
 * 1个对name,age赋值
 * 2个对name,age做变量的输出打印
 */
public class Resource {
    public String name;
    public String sex;
}

线程等待与唤醒案例输入进程:

public class Input implements Runnable{
    private Resource r = new Resource();

    public void run() {
        int i = 0;
        while (true) {
            if (i % 2 == 0) {
                r.name = "张三";
                r.sex = "男";
            } else {
                r.name = "lisi";
                r.sex = "nv";
            }
            i++;
        }
    }
}

线程等待与唤醒案例输出进程:

public class Output implements Runnable{
    private Resource r = new Resource();
    public void run() {
        while(true){
            System.out.println(r.name+"..."+r.sex);
        }
    }
}

线程等待与唤醒案例测试类:

public class ThreadDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Input in = new Input();
        Output out = new Output();

        Thread tin = new Thread(in);
        Thread tout = new Thread(out);

        tin.start();
        tout.start();
    }
}

出现的null值问题是由于r不是同一个。


线程等待与唤醒案例null值解决:

public class Input implements Runnable{
    private Resource r;
    public Input(Resource r){
        this.r = r;
    }

    public void run() {
        int i = 0;
        while (true) {
            if (i % 2 == 0) {
                r.name = "张三";
                r.sex = "男";
            } else {
                r.name = "lisi";
                r.sex = "nv";
            }
            i++;
        }
    }
}

public class Output implements Runnable {
    private Resource r;
    public Output(Resource r){
        this.r = r;
    }
    public void run() {
        while(true){
            System.out.println(r.name+"..."+r.sex);
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Input in = new Input(r);
        Output out = new Output(r);

        Thread tin = new Thread(in);
        Thread tout = new Thread(out);

        tin.start();
        tout.start();
    }
}

线程等待与唤醒案例数据安全解决

public class Resource {
    public String name;
    public String sex;
    public boolean flag = false;
}

public class Input implements Runnable{
    private Resource r;
    public Input(Resource r){
        this.r = r;
    }

    public void run() {
        int i = 0;
        while (true) {
            synchronized (r) {
                if(r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {}
                }
            if (i % 2 == 0) {
                r.name = "张三";
                r.sex = "男";
            } else {
                r.name = "lisi";
                r.sex = "nv";
            }
            //将对方线程唤醒,标记改为true
            r.flag = true;
            r.notify();
            }
            i++;
        }
    }
}

public class Output implements Runnable {
    private Resource r;
    public Output(Resource r){
        this.r = r;
    }
    public void run() {
        while(true){
            synchronized (r) {
                if(!r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {}
                }
                System.out.println(r.name+"..."+r.sex);
                r.flag = false;
                r.notify();
            }
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Input in = new Input(r);
        Output out = new Output(r);

        Thread tin = new Thread(in);
        Thread tout = new Thread(out);

        tin.start();
        tout.start();
    }
}


内容概要:本文介绍了一种用于电磁暂态(EMT)研究的第四类全变流器型风力发电系统的通用Simulink仿真模型,旨在构建一个能够准确反映实际风电系统动态特性的简化通用模型。该模型涵盖了风力机、传动链、发电机、全功率变流器及其控制策略等关键组成部分,重点突出系统在电网故障、风速波动等复杂工况下的动态响应能力,适用于风电并网电磁暂态分析、新型电力系统稳定性评估及高比例可再生能源接入场景的研究。模型设计兼顾准确性与仿真效率,便于研究人员快速搭建和调试,推动风电系统建模与控制技术的发展; 适合人群:具备一定电力系统理论基础和MATLAB/Simulink仿真能力,从事新能源发电、电力电子变换、风电并网控制及相关方向的研究生、科研人员及工程技术人员; 使用场景及目标:①开展风电系统在电网扰动下的电磁暂态仿真分析;②研究全功率变流器风电机组的动态行为与控制特性;③支撑新型电力系统中高渗透率风电接入的稳定性与电能质量评估,服务于学术研究、课程教学与工程项目前期仿真验证; 阅读建议:建议读者结合文中提供的模型结构与参数设置,在Simulink环境中动手复现并调试仿真模型,通过设置不同运行工况(如三相短路、低电压穿越、风速突变等)观察系统响应,深入理解全变流器风电机组的建模方法、控制逻辑与动态特性,进而拓展应用于更复杂的多机并网或综合能源系统仿真场景。
内容概要:本文探讨了Hash算法在芯片行业,特别是网络处理器(NPU)中的性能优化实践,聚焦于如何通过硬件流水线设计实现纳秒级高速哈希查找。文章分析了传统软件哈希方案在高带宽场景下的局限性,提出基于硬件描述语言或高层次综合(HLS)的设计方法,采用CRC32等硬件友好型哈希函数、并行多路哈希、流水线化解耦以及双端口存储结构等核心技术,实现低延迟、无阻塞的数据包处理。通过C++风格的HLS代码示例,展示了从算法选择到资源优化的完整硬件加速逻辑,并深入剖析了循环展开、位宽控制、内存映射和流水线调度等关键实现细节。最后展望了可编程交换机、P4语言支持及TCAM与哈希混合架构等未来发展方向。; 适合人群:具备数字电路基础、熟悉Verilog/SystemVerilog或HLS的芯片设计工程师,以及从事网络芯片、FPGA加速、高性能路由设备研发的技术人员(工作年限1-5年为宜);也适合对硬件加速算法感兴趣的研究人员。; 使用场景及目标:①掌握如何将哈希算法高效映射到硬件逻辑中以满足线速转发需求;②理解流水线设计、资源约束优化、读写冲突规避等在实际芯片项目中的应用;③为开发高性能网络处理器中的流表/路由表查找单元提供技术参考与实现范例。; 阅读建议:学习时应结合HLS工具(如Xilinx Vitis HLS)进行代码仿真与综合,重点关注#pragma指令对硬件结构的影响,并对比不同哈希算法在资源占用与时序表现上的差异,深入理解“空间换时间”的硬件优化本质。
内容概要:本文系统研究了基于粒子群优化(PSO)、灰狼优化(GWO)、鲸鱼优化(WOA)、哈里斯鹰优化(HHO)、蜣螂优化(DBO)和麻雀搜索算法(SSA)六种智能优化算法在无人机三维路径规划中的应用,并在Matlab平台上实现了相应的仿真代码。研究构建了复杂的三维地形与障碍物环境模型,设计了包含路径长度、飞行时间、能耗及安全性等多维度的成本函数,通过定义合理的适应度函数与飞行约束条件,对各类算法的路径搜索能力、收敛速度与规划质量进行了全面对比分析。通过仿真实验验证了各算法在静态复杂环境下的性能表现,旨在为实际无人机任务中优化算法的选择提供科学依据和技术支持。; 适合人群:具备一定Matlab编程基础,从事智能优化算法、无人机路径规划、自动化控制及相关领域研究的研究生、科研人员或工程技术人员。; 使用场景及目标:① 掌握主流群智能优化算法在无人机三维路径规划中的建模与实现方法;② 对比分析不同算法在相同复杂环境下的性能差异,为算法选型提供量化依据;③ 为后续研究动态环境路径规划、多无人机协同任务分配等问题奠定理论与技术基础; 阅读建议:建议读者结合提供的Matlab代码逐模块分析算法实现流程,重点关注适应度函数的设计、障碍物规避策略的实现以及多目标成本函数的权衡机制,同时可通过调整参数设置或引入新型优化算法进行扩展实验,以深化对算法性能的理解与实际应用能力。
内容概要:本文研究了复杂威胁环境下基于多段杜宾斯(Dubins)路径的多无人机协同路径规划问题,提出了一种结合无人机运动学约束与优化算法的协同规划方法。通过Matlab平台实现了路径规划算法的建模与仿真,构建了包含障碍物、禁飞区及动态威胁因素的复杂环境模型,采用优化策略对多无人机系统的飞行路径进行全局协同优化,确保各无人机在满足Dubins路径连续性和曲率约束的前提下,实现任务最优或近优完成。该方法有效解决了多机路径间的冲突规避问题,提升了路径的安全性、可行性和整体效率,具有较强的工程应用价值。; 适合人群:具备一定编程基础和自动化、航空航天、智能无人系统等相关学科背景的科研人员及研究生,尤其适合从事路径规划、多智能体协同控制、智能优化算法研究的专业人士。; 使用场景及目标:①应用于军事侦察、灾害救援、边境巡检、区域监控等多无人机协同作业的实际任务场景;②为复杂环境下多智能体系统的避障、协同决策与路径优化提供算法支持与技术参考;③辅助研究人员复现算法模型,开展进一步的创新性研究与性能对比分析。; 阅读建议:此资源以Matlab代码实现为核心,强调理论与仿真实践相结合,建议读者在掌握Dubins路径基本原理的基础上,结合所提供的代码进行参数调试与仿真实验,深入理解协同优化机制与算法收敛特性,从而提升对多无人机系统路径规划问题的整体认知与研究能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值