java线程的使用_Java 线程的基本使用

创建线程

创建线程的方式有两种:

继承 Thread 类

实现 Runnable 接口

Thread 类实现了 Runnable 接口。使用继承 Thread 类的方式创建线程时,最大的局限是不支持多继承。所以为了支持多继承,应该使用实现 Runnable 接口的方式。两种方式创建的线程在工作时是一样的,没有本质区别。

第一种方式,继承 Thread 类并重写 run() 方法:

public class Work extends Thread {

@Override

public void run() {

System.out.println("Working...");

}

}

public class Run {

public static void main(String[] args) {

Work work = new Work();

work.start();

System.out.println("End!");

}

}

运行结果可能 “End!”先输出。在使用多线程时,运行结果与调用顺序是无关的。

调用 run() 方法只是普通的方法调用,不会启动线程。如果多次调用 start() 方法,会抛出 IllegalThreadStateException 异常。

第二种方式,实现 Runnable 接口:

public class Work implements Runnable {

@Override

public void run() {

System.out.println("Working...");

}

}

public class Run {

public static void main(String[] args) {

Thread t = new Thread(new Work());

t.start();

System.out.println("End!");

}

}

这种方式与第一种在运行上没有什么区别。其优点在于突破了单继承的限制。

Thread 类的部分构造方法:

构造方法

说明

Thread()

创建一个新的线程

Thread(String name)

创建一个新的线程,并指定名称

Thread(Runnable target)

创建一个新的线程,将 target 作为运行对象

Thread(Runnable target, String name)

将 target 作为运行对象,并指定名称

Thread(ThreadGroup group, Runnable target)

将 target 作为运行对象,并作为线程组的一员

线程的方法

currentThread() 方法

currentThread() 方法返回正在被执行的线程的信息。

public class Run() {

public static void main(String[] args) {

System.out.println(Thread.currentThread().getName());

}

}

以上代码在控制台输出 “main“,说明该方法被名为 main 的线程调用。

import static java.lang.System.out;

public class Run {

static class Work extends Thread {

@Override

public void run() {

out.printf("%s 被调用\n", currentThread().getName());

}

}

public static void main(String[] args) {

Work t1 = new Work(),

t2 = new Work();

t1.start();

t2.start();

}

}

以上代码运行结果:

Thread-0 被调用

Thread-1 被调用

Process finished with exit code 0

在 run() 方法中可以省略 Thread 直接调用 currentThread() 方法。

isAlive() 方法

该方法判断当前线程是否处于活动状态。

import static java.lang.System.out;

public class Run {

static class Work extends Thread {

@Override

public void run() {

out.printf("运行中 %s\n", isAlive());

}

}

public static void main(String[] args) throws Throwable {

Work t = new Work();

out.printf("运行前: %s\n", t.isAlive());

t.start();

// 等待线程运行完成

Thread.sleep(1000);

out.printf("运行结束: %s\n", t.isAlive());

}

}

以上代码运行结果:

运行前: false

运行中 true

运行结束: false

Process finished with exit code 0

sleep() 方法

sleep() 方法指定毫秒数让当前线程休眠(暂停运行),该操作不会释放锁。

停止线程

interrupt() 方法

interrupt() 方法并不能立刻停止线程,只是在在线程中打了一个停止的标记。

import static java.lang.System.out;

public class StopThread {

static class Work extends Thread {

@Override

public void run() {

for (int i = 1; i <= 50000; i++) {

out.printf("i = %d\n", i);

}

}

}

public static void main(String[] args) throws Throwable {

Work work = new Work();

work.start();

Thread.sleep(200);

work.interrupt();

out.println("Call interrupt!");

}

}

以上代码运行结果:

...

i = 8190

i = 8191

i = 8192

Call interrupt!

i = 8193

i = 8194

i = 8195

...

interrupt() 方法调用后,线程仍在运行。

要使用 interrupt() 方法停止线程,需要在线程中判断中断状态,有两个方法:

interrupted():测试当前线程是否是中断状态,执行后将状态清除,设置为 false;

isInterrupted():作用同上,但是不清除状态。

import static java.lang.System.out;

public class StopThread {

static class Work extends Thread {

@Override

public void run() {

for (int i = 1; i <= 50000; i++) {

if (isInterrupted()) {

out.println("跳出循环!");

break;

}

out.printf("i = %d\n", i);

}

}

}

public static void main(String[] args) throws Throwable {

Work work = new Work();

work.start();

Thread.sleep(200);

work.interrupt();

out.println("Call interrupt!");

}

}

以上代码执行结果:

...

i = 8301

i = 8302

i = 8303

i = 8304

i = 8305

i = 8306

i = 8307

Call interrupt!

跳出循环!

Process finished with exit code 0

在调用 interrupt() 方法后,循环已经退出。但是这种方式只是跳出了循环,假如 for 循环外还有代码,仍然会执行。

抛出异常停止线程

可以在判断线程状态为中断时,抛出一个异常,在 catch 或 finally 块中做中断后的处理:

import static java.lang.System.out;

public class StopThread {

static class Work extends Thread {

@Override

public void run() {

try {

for (int i = 1; i <= 50000; i++) {

if (isInterrupted()) {

out.println("Interrupted!");

throw new InterruptedException("抛出异常!");

}

out.printf("i = %d\n", i);

}

out.println("for 循环结束!");

} catch (InterruptedException e) {

out.println(e.getMessage());

}

}

}

public static void main(String[] args) throws Throwable {

Work work = new Work();

work.start();

Thread.sleep(200);

work.interrupt();

out.println("Call interrupt!");

}

}

以上代码将线程要执行的任务放入 try 块中,当判断为中断状态时,抛出 InterruptedException ,如果需要释放锁,可以在 finally 块中执行。

也可以配合 return 来停止线程:

if (isInterrupted()) {

return;

}

暂停线程

Java 提供了 suspend() 和 resume() 方法来暂停和恢复线程,不过这两个方法已经过期作废了。

suspend() 方法暂停线程时,不会释放锁。所以使用 suspend() 方法容易产生死锁。

如果需要暂停线程,可以加入一个标记,若标记指出线程需要暂停,使用 wait() 进入等待状态,如需要恢复,使用 notify() 唤醒。

import static java.lang.System.out;

public class StopThread {

static class Work extends Thread {

// 暂停标记

private boolean isSuspended = false;

void pause() {

isSuspended = true;

}

synchronized void wake() {

isSuspended = false;

// 唤醒

this.notify();

out.println("已唤醒!");

}

@Override

public void run() {

synchronized (this) {

try {

for (int i = 1; i <= 5000; i++) {

if (isInterrupted()) {

return;

}

if (isSuspended) {

out.println("已暂停!");

// 等待

this.wait();

}

out.printf("%s i = %d\n", getName(), i);

}

out.printf("%s end!\n", getName());

} catch (InterruptedException e) {

out.println(e.getMessage());

}

}

}

}

public static void main(String[] args) throws Throwable {

Work work = new Work();

work.start();

Thread.sleep(100);

// 暂停

work.pause();

Thread.sleep(100);

// 唤醒

work.wake();

}

}

以上代码使用 wait() 和 notify() 暂停与恢复线程。运行结果:

...

Thread-0 i = 202

Thread-0 i = 203

Thread-0 i = 204

已暂停!

已唤醒!

Thread-0 i = 205

Thread-0 i = 206

Thread-0 i = 207

...

Thread-0 i = 4998

Thread-0 i = 4999

Thread-0 i = 5000

Thread-0 end!

Process finished with exit code 0

yield 方法

yield() 方法的作用是放弃当前的 CPU 资源,让其他的任务去占用 CPU 执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得时间片。

import static java.lang.System.currentTimeMillis;

import static java.lang.System.out;

public class Yield {

static class Work extends Thread {

@Override

public void run() {

long before = currentTimeMillis();

int sum = 0;

for (int i =1; i < 2000000; i++) {

// yield();

sum += (i + 1);

}

long after = currentTimeMillis();

out.printf("Cost: %dms\n", after - before);

}

}

public static void main(String[] args) {

new Work().start();

}

}

以上代码不使用 yield() 方法时大概 15ms 执行完,加上后大概有 500ms。

你可能感兴趣的:(java线程的使用)