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。

Java 线程的基本使用的更多相关文章

  1. Java线程并发:知识点

    Java线程并发:知识点   发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用.   逃逸:在对象尚未准备 ...

  2. Java线程的概念

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  3. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  4. 细说进程五种状态的生老病死——双胞胎兄弟Java线程

    java线程的五种状态其实要真正高清,只需要明白计算机操作系统中进程的知识,原理都是相同的. 系统根据PCB结构中的状态值控制进程. 单CPU系统中,任一时刻处于执行状态的进程只有一个. 进程的五种状 ...

  5. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

  6. 第24章 java线程(3)-线程的生命周期

    java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...

  7. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  8. 第22章 java线程(2)-线程同步

    java线程(2)-线程同步 本节主要是在前面吃苹果的基础上发现问题,然后提出三种解决方式 1.线程不安全问题 什么叫线程不安全呢 即当多线程并发访问同一个资源对象的时候,可能出现不安全的问题 对于前 ...

  9. 第21章 java线程(1)-线程初步

    java线程(1)-线程初步 1.并行和并发 并行和并发是即相似又有区别: 并行:指两个或者多个事件在同一时刻点发生. 并发:指两个或多个事件在同一时间段内发生 在操作系统中,并发性是指在一段事件内宏 ...

  10. [转]Java线程安全总结

    最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣.已经拟好了提纲,大概分为这几个主题: java线程安全,java垃圾收集,java并发包详细介绍,java profi ...

随机推荐

  1. 考研辅助app的诞生!

    背景: 去年下半年由于种种因素驱动下,准备去考研,在之前同事的推荐下,参加了考研培训班,培训班发了纸质书籍和线上视频观看账号,由于线上视频需要全程联网才能观看,突发奇想,要是我把这些视频下载下来,没网 ...

  2. 章节十四、9-Actions类鼠标悬停、滚动条、拖拽页面上的元素

    一.鼠标悬停 1.在web网站中,有一些页面元素只需要我们将鼠标指针放在上面就会出现被隐藏的下拉框或者其它元素,在自动化的过程中我们使用Actions类对鼠标进行悬停操作. 2.案例演示 packag ...

  3. Codeforces Round #304 (Div. 2)(CF546E) Soldier and Traveling(最大流)

    题意 给定 n 个城市,m 条边.人只能从走相邻边相连(只能走一次)的城市. 现在给你初始城市的每一个人数,再给一组每个城市人数.询问是否可以从当前人数变换到给定人数.如果能,输入"YES& ...

  4. JS高阶---浏览器内核

    不同浏览器的内核,不太一样 360双核切换机制 一般涉及到金钱交易时,会切换到Trident内核,因为IE内核安全性较稳 不涉及金钱利益时,则会使用webkit内核 (1)内核是由很多模块构成 注意: ...

  5. socket服务

    1.socket_server import socket import threading server = socket.socket(socket.AF_INET, socket.SOCK_ST ...

  6. CF1045B Space Isaac

    原题链接 DOWNLOAD AS PDF 题目大意 \(0\sim m-1\)的数被分成两个集合,你可以分别从两个集合中取一个数相加并对\(m\)取模,求一不能构造出的数. 题解 感觉如果\(\col ...

  7. K12

    K12,教育类专用名词(kindergarten through twelfth grade),是学前教育至高中教育的缩写,现在普遍被用来代指基础教育. K-12教育是美国基础教育的统称.“K12”中 ...

  8. 数据结构or算法

    其实长久以来 mrxfyxj一直纠结着数据结构和算法到底有什么区别 只要学了一个算法就在惋惜她为什么不能是数据结构 产生这种想法的原因是mrxf觉得他blog里数据结构的东西很少 而mrxf自身又有一 ...

  9. 第02组 Beta冲刺(2/4)

    队名:十一个憨批 组长博客 作业博客 组长黄智 过去两天完成的任务:了解整个游戏的流程 GitHub签入记录 接下来的计划:继续完成游戏 还剩下哪些任务:完成游戏 燃尽图 遇到的困难:没有美术比较好的 ...

  10. AtCoder Grand Contest 035

    Preface Atcoder的题都好劲啊,都是我做不动的计数与构造 就当锻炼自己的思维能力了(基本都是bzt教的) A - XOR Circle bzt说这题数据太水了只要判一下所有数异或值是否为\ ...