Java多线程入门
创建线程的三种方式
继承Thread类
class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + " " + i); } } public static void main(String[] args) { new MyThread().start(); new MyThread().start(); new MyThread().start(); } }
实现Runnable接口
class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + " " + i); } } public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable, "T1").start(); new Thread(myRunnable, "T2").start(); new Thread(myRunnable, "T3").start(); } }
实现Callable接口
class CallerTask implements Callable<String> { @Override public String call() throws Exception { return "回调结果"; } public static void main(String[] args) { // 创建异步任务 FutureTask<String> task = new FutureTask<>(new CallerTask()); // 启动线程 new Thread(task).start(); try { // 等待执行完成,并获取返回结果 String result = task.get(); System.out.println(result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
-
run()
:封装线程执行的代码,直接调用相当于调用普通方法。 -
start()
:启动线程,然后由 JVM 调用此线程的run()
方法。 -
实现 Runnable 接口避免了 Java 单继承的局限性,Java 不支持多重继承,因此如果我们的类已经继承了另一个类,就不能再继承 Thread 类了。并且适合多个相同的程序代码去处理同一资源的情况,把线程、代码和数据有效的分离,更符合面向对象的设计思想。Callable 接口与 Runnable 非常相似,但可以返回一个结果。
控制线程的其他方法
-
sleep():使当前正在执行的线程暂停指定的毫秒数,也就是进入休眠的状态。
-
join():等待这个线程执行完才会轮到后续线程得到 cpu 的执行权。
public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread(myRunnable, "T1"); t1.start(); try { // t1执行完才会轮到后面的线程执行 t1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } new Thread(myRunnable, "T2").start(); new Thread(myRunnable, "T3").start(); }
-
setDaemon():将此线程标记为守护线程,准确来说,就是服务其他的线程,像 Java 中的垃圾回收线程,就是典型的守护线程。
-
yield():yield() 方法是一个静态方法,用于暗示当前线程愿意放弃其当前的时间片,允许其他线程执行。然而,它只是向线程调度器提出建议,调度器可能会忽略这个建议。具体行为取决于操作系统和 JVM 的线程调度策略。
class YieldExample { public static void main(String[] args) { Thread thread1 = new Thread(YieldExample::printNumbers, "刘备"); Thread thread2 = new Thread(YieldExample::printNumbers, "关羽"); thread1.start(); thread2.start(); /* 关羽 让出控制权... 刘备 让出控制权... 关羽: 3 关羽: 4 关羽 让出控制权... // 即便有时候让出了控制权,其他线程也不一定会执行 关羽: 5 刘备: 3 刘备: 4 刘备 让出控制权... 刘备: 5 */ } private static void printNumbers() { for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + ": " + i); // 当 i 是偶数时,当前线程暂停执行 if (i % 2 == 0) { System.out.println(Thread.currentThread().getName() + " 让出控制权..."); Thread.yield(); } } } }
线程的生命周期
本文作者:n1ce2cv
本文链接:https://www.cnblogs.com/sprinining/p/18310244
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!