java多线程api_一、Java多线程编程 (基础篇)

一、进程和线程

进程是受操作系统管理的基本运行单元,我们可以把windows操作系统上运行的一个exe程序理解成一个进程,也可以把Android操作系统上运行的一个app理解成一个进程。

线程我们可以理解成是在进程中独立运行的子任务,比如QQ.exe运行的时候我们可以发消息,视频通话,上传文件等。这每一项任务我们都可以理解成是线程在工作。

使用多线程有什么优点?

使用多线程可以最大限度的利用cpu的空闲时间来处理其他任务,比如一边让操作系统处理正在打印的数据,一边使用Word编辑文档。CPU在这些任务之间不停的切换,由于切换的速度非常快,给使用者的感受就是这些任务几乎是同时执行的。

0fc0f05071bc

image.png

以上图1-3我们发现在单任务也就是单线程的情况下,任务2必须要等待任务1执行完才能执行。而在1-4中我们使用多线程的情况下,任务2不需要等待任务1执行完毕,CPU可以在任务1和2之间来回的切换。

二、使用多线程

在Java的JDK开发包中已经自带了对多线程技术的支持。实现多线程编程的方式主要有两种,一种是继承Thread,一种是实现Runnable接口。

1、继承Thread

package com.company;

public class Main {

public static void main(String[] args) {

InnerThread t = new InnerThread();

t.start();

}

}

class InnerThread extends Thread {

@Override

public void run() {

super.run();

System.out.println("使用继承Thread启动了一个线程");

}

}

使用继承Thread启动了一个线程

我们创建了一个InnerThread 类,继承了Thread,并重写了run方法。在main函数中我们创建InnerThread 对象,并调用了start方法,这样就启动了一个线程。线程的工作就是在run方法中。

2、实现Runnable接口

package com.company;

public class Main {

public static void main(String[] args) {

Thread t = new Thread(new MyRunnable());

t.start();

}

}

class MyRunnable implements Runnable {

@Override

public void run() {

System.out.println("使用继实现Runnable启动了一个线程");

}

}

使用继实现Runnable启动了一个线程

以上我们使用实现Runnable接口也启动了一个线程。线程具体的工作在Runnable接口的run方法中。我们可以看到Thread类其实也实现了Runnable接口

public

class Thread implements Runnable {

/* Make sure registerNatives is the first thing does. */

private static native void registerNatives();

static {

registerNatives();

}

我们也可以通过传入Thread对象的方式启动一个线程,其实和实现Runnable是一样的。

package com.company;

public class Main {

public static void main(String[] args) {

Thread t = new Thread(new MyThread());

t.start();

}

}

class MyThread extends Thread {

@Override

public void run() {

super.run();

System.out.println("通过传入Thread对象的方式启动一个线程");

}

}

通过传入Thread对象的方式启动一个线程

三、Thread的一些常用Api

1、Thread.currentThread()

currentThread方法,指的是获取当前代码块运行所在的线程。

package com.company;

public class Main {

public static void main(String[] args) {

Thread t = new Thread(new MyRunnable());

t.start();

System.out.println("1、当前线程:"+Thread.currentThread().getName());

}

}

class MyRunnable implements Runnable {

@Override

public void run() {

System.out.println("2、当前线程:"+Thread.currentThread().getName());

}

}

1、当前线程:main

2、当前线程:Thread-0

我们可以看到main方法运行所在的线程的名字为main,而MyRunnable中的run方法运行所在的线程名字为Thread-0

2、isAlive()方法

判断当前线程是否处于活动的状态。活动状态指的是线程已经启动尚未终止,即线程处于正在运行或者准备开始运行的状态。

public class Main {

public static void main(String[] args) {

Thread t = new Thread(new MyRunnable());

t.start();

System.out.println("1当前线程状态:"+t.isAlive());

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("2当前线程状态:"+t.isAlive());

}

}

class MyRunnable implements Runnable {

@Override

public void run() {

}

}

1当前线程状态:true

2当前线程状态:false

在代码中我们可以理解成调用start方法后线程变为活动的状态。以上我们看到调用start方法只会,由于我们启动的线程没有马上执行完毕,我们打印了isAlive结果是true,当我们在main方法中休眠了1000毫秒,之后再去打印isAlive,我们启动的线程已经执行完毕,所以结果是false。在上面的例子我们我们其实有两个线程,一个是main方法所在的main线程,一个是我们启动的线程,我们可以叫他做A线程。我们在main函数所在的线程中启动了一个A线程,这两个线程是异步执行任务,不需要排队执行。启动A线程之后,我们休眠了1000毫秒,我们休眠的线程是Main线程,对A线程没有影响,当我们再去打印A线程的isAlive方法的时候,结果是false,因为过了1000毫秒,A线程已经执行完毕,处于非活动状态。

3、sleep

让当前线程休眠(暂停执行)一段时间。

package com.company;

public class Main {

public static void main(String[] args) {

Thread t = new Thread(new MyRunnable());

t.start();

System.out.println("我们在"+Thread.currentThread().getName()+"休眠了1000毫秒");

}

}

class MyRunnable implements Runnable {

@Override

public void run() {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("我们在"+Thread.currentThread().getName()+"休眠了1000毫秒");

}

}

我们在main休眠了1000毫秒

我们在Thread-0休眠了1000毫秒

4、interrupt方法

使用interrupt方法来终止线程。

package com.company;

public class Main {

public static void main(String[] args) {

MyThread t = new MyThread();

t.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

t.interrupt();

}

}

class MyThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 500000; i++) {

if (isInterrupted()) {

break;

}

System.out.println("我正在执行..." + i);

}

System.out.println("执行完毕");

}

}

我正在执行...

我正在执行...

我正在执行...

我正在执行...

我正在执行...

我正在执行...

我正在执行...

我正在执行...

true

执行完毕

在上面的例子中,我们在线程的run方法中,写了一个for循环,通过isInterrupted的返回值来判断是否跳出循环,结束循环里的工作。在Main方法中,我们启动了一个线程,休眠1000毫秒之后,我们调用interrupt方法,中断了线程。所以看到以上的打印结果是执行了一段时间for循环里的代码之后,跳出循环并打印了执行完毕。以上的方式我们可以结束掉for循环里的工作。但是线程没有真正被执行完毕,因为后面还是打印了执行完毕的字样,说明线程还是在工作。那我们怎么样才能真正的停止线程呢?

package com.company;

public class Main {

public static void main(String[] args) {

MyThread t = new MyThread();

t.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

t.interrupt();

}

}

class MyThread extends Thread {

@Override

public void run() {

try {

for (int i = 0; i < 500000; i++) {

if (isInterrupted()) {

throw new InterruptedException();

}

System.out.println("我正在执行..." + i);

}

System.out.println("执行完毕");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

我正在执行...177357

我正在执行...177358

我正在执行...177359

我正在执行...177360

我正在执行...177361

我正在执行...177362

我正在执行...177363

我正在执行...177364

我正在执行...177365

我正在执行...177366

我正在执行...177367

我正在执行...177368

java.lang.InterruptedException

at com.company.MyThread.run(Main.java:22)

我们通过抛出InterruptedException异常的方式来停止线程,我没看到执行完毕这几个字样没有执行了。

5、yield

yield方法指的是放弃当前CPU资源,给其他线程去占用CPU资源。但是放弃时间不确定,有可能刚放弃又马上获得CPU时间片。因为CPU调度线程是随机的。

6、线程的优先级

通过setPriority方法可以设置线程的优先级,我们知道CPU调度线程是随机的,设置线程的优先级越高,可以使得线程获得CPU的资源越多。也就是CPU优先执行优先级高的线程。

优先级具有继承性

A线程启动B线程,那么A线程和B线程的优先级一样

优先级具有规则性和随机性

优先级具有规则性指的是:CPU会尽量将执行资源让给优先级比较高的,但是不是完全的。

优先级具有随机性指的是:优先级高的线程不代表任务一定能执行完,也有可能优先级低的任务先执行完了。但是大概率会是优先级高的会优先执行完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值