java多线程调用一个函数_Java 多线程(一)

本文介绍了Java中实现多线程的两种主要方式:继承Thread类和实现Runnable接口,并通过示例代码详细展示了每种方式的用法。推荐使用Runnable接口,因为它可以规避单继承限制并允许线程共享资源。此外,文章还概述了线程状态的转换以及常用线程函数如sleep、yield、join和线程优先级等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 多线程使用方法

使用多线程,绝大部分情况都是通过如下两种方式实现的,即继承Thread类或者实现Runnable接口。以下对两种方式分别进行介绍并比较。

1.1 使用Thread类实现多线程

自定义线程类要继承 Thread 类,并在 run 方法中实现自己的逻辑。参数的传递,可以采用构造方法传参或者设值的方式。

public class MyThread extends Thread

{

private String name;

public MyThread(String name)

{

this.name = name;

}

public void run()

{

for (int i = 0;i < 5;i++)

{

System.out.println("Thread name is " + name + ", say hello " + i);

try

{

Thread.sleep(500);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

public static void main(String[] args)

{

Thread alice = new MyThread("Alice");

Thread bob = new MyThread("Bob");

alice.start();

bob.start();

}

}

1.2 使用Runnable接口实现多线程

自定义线程类要实现 Runnable 接口,重写 run 方法。参数的传递,可以采用构造方法传参或者设值的方式。

package com.example.demo.mutilThread;

public class MyRunnable implements Runnable

{

private String name;

public MyRunnable(String name)

{

this.name = name;

}

public void run()

{

for (int i = 0;i < 5;i++)

{

System.out.println("RunnableThread name is " + name + ", say hello " + i);

try

{

Thread.sleep(500);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

public static void main(String[] args)

{

Thread cache = new Thread(new MyRunnable("Cache"));

Thread dodge = new Thread(new MyRunnable("Dodge"));

cache.start();

dodge.start();

}

}

1.3 小结

线程创建完毕之后,调用Thread的start方法,该并不是直接开始执行该线程,而是将该线程设置成为可运行的状态,即随时都都可以运行。至于什么时候真正的开始运行,是由操作系统的调度决定的。

在自定义线程类中重写的是run方法,但是在使用多线程的时候,调用的是start方法。打开start方法的实现,可以看到其中调用了本地方法start0,而在该方法中,最终调用了线程实例的run方法。如果在主线程中不使用start,而是使用run方法,那么则不会新开辟一个线程来执行其中的逻辑,而是直接在主线程中执行,跟普通的方法一样。

通过执行结果可以看到,多个线程之间的程序执行是乱序的,并不是每个线程按照某种固定的顺序执行。但是可以通过设计对应的控制逻辑,使得多个线程的执行变得有序。

对比两种方式,其实更加推荐使用Runnable的方式,因为实现Runnable接口,可以规避java中的单继承的限制,并且对于线程池来说,不能直接放入继承Thread的类。另外,Runnable的代码可以被多个线程共享(即用一个Runnable实现类初始化多个Thread实例),适合于多个线程处理同一资源的情况,比如买票场景。

2.线程状态

线程的各个状态以及之间的转换条件和路径如下图所示:

AAffA0nNPuCLAAAAAElFTkSuQmCC

初始状态:Thread实例初始化完成。

可运行状态:调用线程实例的start方法后,线程进入到可运行线程池中等待运行。

运行状态:处于可运行状态的线程获取到了CPU,进入到运行状态,开始执行线程逻辑。

阻塞状态:阻塞状态是因为处于正在运行状态的线程放弃CPU。一般阻塞状态分为3种:

等待阻塞:线程执行了对象的wait方法。此时线程会释放持有的锁,被放置进入JVM的等待池中。

同步阻塞:线程在尝试获取同步锁失败,被放置进入锁池中。

其他阻塞:调用sleep方法或者join方法,或者等待IO的时候。

死亡状态:线程执行完毕或者异常退出run方法。

3 常用函数

Thread.sleep() 函数:该函数会使对应的线程休眠指定毫秒的时间。休眠结束之后会进入到可运行状态。执行休眠的时候不会释放锁。

Thread.yield() 函数:该函数会使当前线程让出CPU,从运行状态变成可运行状态。之后所有处于可运行状态的线程竞争CPU。高优先级的线程会优先被OS调度执行。如果是相同优先级,则平等竞争,但是存在一种情况是,让出CPU的线程被OS再次选中执行。需要注意的是,yield函数不会导致线程转到阻塞状态。

thread.join() 函数:该方法是让当前线程等待其他线程终止。比如在A线程中调用线程B.join(),那么执行的效果就是线程A从运行状态变成阻塞状态,一直等待线程B执行完毕,线程A才会转为可运行状态。join方法一般用于主线程中需要使用子线程的执行结果的情况。

thread.setPriority() 函数:设置线程的执行优先级。java的线程包含10个优先级,用1-10表示,数字越大,优先级越高。默认的优先级是5.

/**

* The minimum priority that a thread can have.

*/

public final static int MIN_PRIORITY = 1;

/**

* The default priority that is assigned to a thread.

*/

public final static int NORM_PRIORITY = 5;

/**

* The maximum priority that a thread can have.

*/

public final static int MAX_PRIORITY = 10;

object.wait()函数:该函数在synchronized代码块中使用,作用是使当前线程进入到等待状态,并释放锁。直到其他线程调用该对象的notify或者notifyAll方法进行唤醒,被唤醒之后,需要首先获取到对象锁,才能执行逻辑。

object.notify()函数:唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程唤醒。

object.notifyAll()函数:功能与notify类似,不同点在于notifyAll函数唤醒对象监视器上等待的所有线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值