GitHub Page: http://blog.cloudli.top/posts/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 循环外还有代码,仍然会执行。

抛出异常停止线程

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

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。

最新文章

  1. JavaScript 动态脚本
  2. leetcode 解题报告 Word Break
  3. opencv矩阵总结
  4. 在eclipse中将项目发布到tomcat的root目录
  5. MongoDB源码分析——mongod程序源码入口分析
  6. PHP5.6.x的新鲜事
  7. 使用Teleport Pro离线下载网页所有内容
  8. Three.js 3D打印数据模型文件(.STL)载入中
  9. 浙江大学PAT考试1009~1012(1010上帝是冠军。。)
  10. POJ1144(割点)
  11. 腾讯云分布式高可靠消息队列服务CMQ架构
  12. python pyqt绘制直方图
  13. JVM 辣鸡回收
  14. PHP操作MongoDB 数据库
  15. Java中类的构造方法
  16. 深度学习主机环境配置: Ubuntu16.04+GeForce GTX 1080+TensorFlow
  17. (转)每天一个linux命令(21):find命令之xargs
  18. POJ3070 Fibonacci[矩阵乘法]【学习笔记】
  19. [RTC]系统和RTC的时间保持一致
  20. MT【128】不动点指路

热门文章

  1. android studio学习----gradle命令详解
  2. PMP备考-第一章-引论
  3. linux 进程通信之 mmap
  4. Hebye 深度学习中Dropout原理解析
  5. scanf的返回值
  6. 接口测试 从 0 到 1,用 Jmeter 搭建 HTTP 接口自动化引擎 1.0 版本
  7. 1.python进行if条件相等时候的条件
  8. 【Spring IoC】BeanFactory 和 ApplicationContext(五)
  9. 搭建Dubbo Admin(五)
  10. SLAM: