1. 主页 > 小妙招

Java启动线程的3种方法详解:Thread、Runnable与Lambda示例

你是不是刚学Java,面对“线程”这词儿就头皮发麻?别慌!今天咱们就用最接地气的方式,把Java启动线程的三大绝活掰开揉碎了讲明白。我刚开始学的时候也觉得这玩意儿玄乎,后来才发现其实就是一层窗户纸——捅破了就透亮!


一、最原始的招式:直接继承Thread类

(敲黑板)这是教科书里必讲的祖传方法,??extends Thread??这个操作就跟盖章似的,谁用谁知道。咱们直接上案例:

java复制
// 举个卖票的例子
class TicketSeller extends Thread {
    private int tickets = 10;
    
    @Override
    public void run() {
        while(tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + tickets-- + "张票");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        new TicketSeller().start();
        new TicketSeller().start();
    }
}

??重点来了:??

  1. 必须重写run()方法,这里头放你要干的活儿
  2. 调用start()而不是直接调用run()(划重点!直接调用run就成普通方法了)
  3. 每个Thread对象都是独立作战的士兵

不过啊,这方法有个硬伤——Java是单继承的!你继承了Thread就不能继承其他类了。这时候你可能会问:那我要继承其他类怎么办?别急,往下看!


二、灵活度爆表的玩法:实现Runnable接口

(拍大腿)这才是业界公认的正确打开方式!??implements Runnable??这招就像穿松紧裤——弹性十足还不勒肚子。咱们把刚才的卖票案例改造一下:

java复制
class TicketWindow implements Runnable {
    private int tickets = 10;
    
    @Override
    public void run() {
        while(tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "窗口卖出第" + tickets-- + "张票");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Runnable task = new TicketWindow();
        new Thread(task, "北京西站").start();
        new Thread(task, "上海虹桥").start();
    }
}

??划重点对比:??

  • ?? 可以继承其他类(终于不用在Thread一棵树上吊死了)
  • ?? 多个线程共享同一个Runnable实例(像上面的票数就是共享的)
  • ?? 更符合面向对象的设计思想(把任务和线程本身解耦)

不过我发现新手常掉这个坑:明明用了Runnable,为什么票数卖超了?这就是线程安全问题啦,咱们后面再说这个。


三、新时代的骚操作:Lambda表达式

(吹口哨)Java8带来的这个神器,简直是懒癌患者的福音!以前要写一坨代码,现在一行搞定。来看怎么用Lambda启动线程:

java复制
public class LambdaThread {
    public static void main(String[] args) {
        // 终极精简版
        new Thread(() -> {
            System.out.println("我在用Lambda飞起~");
        }).start();
        
        // 带参数的玩法
        Runnable task = () -> System.out.println("连run都省了!");
        new Thread(task).start();
    }
}

??为什么推荐这个:??

  1. 代码量直接砍半(程序员的手腕健康就靠它了)
  2. 不用定义单独的类(临时任务简直不要太方便)
  3. 看着就高大上(装X必备技能)

不过要提醒各位萌新:Lambda虽好,可不要贪杯哦!复杂逻辑还是老老实实用传统写法更清晰。


四、选哪个方法好?老司机掏心窝建议

这三种方法就像吃饭用的筷子、叉子、手抓——没有绝对的好坏,关键看场合:

  1. 临时小任务 → ??Lambda??(方便快捷)
  2. 需要资源共享 → ??Runnable??(灵活可靠)
  3. 简单测试 → ??Thread??(随手就来)

但有个血泪教训要分享:千万别在项目中无脑用Thread继承!我之前接手过一个老项目,满屏的Thread子类,改个需求就跟拆炸弹似的,生怕动了哪个线程...


五、躲开这些坑,你就能超越80%的新手

  1. ??start()和run()傻傻分不清??
    (举个栗子)把start()换成run(),程序也能跑,但这就变成单线程了!好比本来要开五台收割机收麦子,结果变成一个人开五趟...

  2. ??线程安全问题防不胜防??
    就像十个人同时往一个存钱罐塞钱,不加锁的话,最后数目肯定对不上。解决方案要么加synchronized,要么用原子类。

  3. ??线程池才是终极形态??
    虽然今天没细讲,但提前剧透:直接new Thread就像每次吃饭都新买双筷子,用线程池才是正经人家的做法,省资源又高效。


个人观点时间

用了这么多年Java线程,我最想说的是:??不要为了炫技而写复杂代码??!见过有人非要把Lambda嵌套五层显示水平,结果三个月后自己都看不懂。代码首先是给人看的,其次才是给机器执行。

最后送大家一句话:线程不是洪水猛兽,把它想象成流水线上的工人,你当好包工头安排好任务就行。刚开始可能会被调度问题搞得头大,但多踩几次坑自然就开窍了。编程嘛,不就是bug叠着bug成长起来的?

本文由嘻道妙招独家原创,未经允许,严禁转载