Java学习笔记(46)——线程
这里将自己学习java及其应用的一些笔记、积累分享一下,如果涉及到了文章、文字侵权,请联系我删除或调整。
一、线程
1.1 概述
进程、线程、操作系统的关系。
- 进程
操作系统中,并行执行的任务
- 线程
进程内部,并行执行的任务
- 操作系统、进程、线程之间的关系可简单描述如下:
二、创建线程
2.1 概述
创建线程,主要包括以下两种方式:
- 继承 Thread
- 实现 Runnable
需要了解的是,在JVM虚拟机启动后,会自动启动一个main线程。
2.2 继承 Thread 方式
- 定义 Thread 的子类
- 重写 run() 方法
- 在 run() 方法中的代码,是与其他代码并行执行的代码
- 线程启动后,自动自动执行 run() 方法
2.2.1 练习:通过继承Thread创建线程
在下例中,我们通过继承 Thread 的方式,创建了2个线程,并重写了 run() 方法,该方法实现了循环打印。由于线程的执行是基于cpu的时间片机制的,因此,我们在实际执行时,可以看到每个线程的打印内容,并不一定是连续的(如若不明显,可增加循环次数,例如1-1000,因为由于循环次数较短,可能在一个时间片内就完成了)。
package 线程;
public class Test_线程创建测试 {
// JVM虚拟机启动后,会自动启动一个main线程
public static void main(String[] args) {
T1 t1 = new T1();
T1 t2 = new T1();
// 线程启动后,run方法自动执行
// .start()方法启动线程
t1.start();
t2.start();
System.out.println("main");
}
static class T1 extends Thread{
@Override
public void run() {
// 获得线程名字,setName可以设置任意线程名,默认名字Thread-0...
String n = getName();
// 打印1-5
for(int i=1 ;i<=5;i++) {
System.out.println(n+":"+i);
}
}
}
}
2.3 实现 Runable 接口方式
- 定义Runnable子类
- 实现run() 方法
- 把Runnable 对象,放入 Thread 线程对象启动
- 线程启动后,执行 Runnable 对象的 run() 方法
2.3.1 练习:通过实现Runable接口创建线程
package 线程;
public class Test_Runable接口_线程 {
public static void main(String[] args) {
R1 r1 = new R1();
R1 r2 = new R1();
// 把Runnable 对象,放入 Thread 线程对象启动
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r1);
// 线程启动后,自动执行r1.run方法
t1.start();// 虽然都是传入的r1,但却各自维护这个一个r1的run
t2.start();
System.out.println("main");
}
static class R1 implements Runnable{
@Override
public void run() {
// 获得正在执行这行代码的线程对象
Thread t = Thread.currentThread();// Thread静态方法
// 因为没有继承Thread的方法,所以不能直接调用getName
String name = t.getName();
for(int i = 1;i<=10;i++) {
System.out.println(name+":"+i);
}
}
}
}
三、线程的状态
3.1 概述
线程的状态可简单分为“新生”、“可执行”、“阻塞”、“执行”、“消亡”。我们可以通过如下一个简图来了解状态之间的关系。
四、线程的方法
4.1 方法简介
- Thread.currentThread()
获得正在执行这行代码的线程对象
- Thread.sleep(毫秒值)
当前线程暂停指定的毫秒时长
- Thread.yield()
让步,当前线程放弃时间片,让出cpu资源
- getName(),setName()
获取线程名称、设置线程名称
- start()
启动线程
- iterrupt()
打断一个线程的暂停状态,被打断的线程出现InterruptedException
- join()
当前线程,等待被调用的线程结束
- getPriority(), setPriority()
获取 / 设置优先级,1到10,默认5
- setDaemon(true)
调用Thread对象的setDaemon(true)方法,可将指定线程设置成后台线程、守护线程。
注意!后台线程有个特征:如果所有的前台线程都消亡了,后台线程会自动消亡。当整个虚拟机中只剩下后台线程时,程序就没有继续运行的必要了,虚拟机也就退出了。JVM的垃圾回收线程就是典型的后台线程。main线程默认是前台线程,但并不是所有的线程默认都是前台线程,有些线程默认就是后台线程——前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程。
4.2 练习:Threadsleep_Interrupted测试
package 线程;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test_Threadsleep_Interrupted测试 {
public static void main(String[] args) {
T1 t1= new T1();
t1.start();
// 在main线程中,打断t1线程的暂停状态
System.out.println("回车打断t1线程");
// 因为t1与main是两个并行的线程,所以,互不影响
// 因此,“等待输入回车”与时间每秒打印互不影响
new Scanner(System.in).nextLine();
t1.interrupt();
}
static class T1 extends Thread{
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
while(true) {
String s = sdf.format(new Date());
System.out.println("当前时间:"+s);
// 停1秒,因为CPU效率极高,在一秒内可以打印多次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 忽略了该异常,暂不处理
System.out.println("t1进程被打断!");
break;
}
}
}
}
}
4.3 练习:Join测试
package 线程;
/*
* PC端,一个CPU的情况下,多线程依旧时间效率更高,原因是
* 操作系统会给线程更多的进程任务分配更多的系统资源
*/
public class Test_Join测试 {
public static void main(String[] args) throws InterruptedException {
// 1000万内的质数数量,多线程进行分段计算
// System.out.println("单线程");
// f1();
System.out.println("5个线程");
f2();
}
// 单线程计算1000万以内的质数
private static void f1() throws InterruptedException {
long t = System.currentTimeMillis();
T1 t1 = new T1(0, 10000000);
t1.start();
/* .start()方法启用线程,不可替代
*
* 此处,如果用.start()启动线程,则质数打印结果不准确,
* 为1或几个。原因是,线程启动后,由于CPU分片机制,导致
* main线程的指令也可能分到时间片而执行后续的代码,此时,
* count被赋值且执行了打印语句
*/
t1.join();// .join()方法,当前线程等待,调用对象线程优先执行至结束
int count = t1.count;// 质数个数
t = System.currentTimeMillis()-t;
System.out.println("单线程用时"+t);
System.out.println("质数个数为:"+count);
}
// 多线程计算1000万以内的质数
private static void f2() throws InterruptedException {
long t = System.currentTimeMillis();
T1[] t2 = new T1[5];
for(int i = 0;i<t2.length;i++) {
t2[i] = new T1(2000000*i,2000000*(i+1));
t2[i].start();
}
// main线程等待,5个线程先行计算
// join与start分开,是为了保证5个线程并行
int count =0;// 统计每个线程的质数数量
for(int i = 0;i<t2.length;i++) {
t2[i].join();
count += t2[i].count;
}
t = System.currentTimeMillis()-t;
System.out.println("5线程用时"+t);
System.out.println("质数个数为:"+count);
}
static class T1 extends Thread{
int start,end;
int count;// 统计质数的个数
// 构造方法
public T1(int start, int end) {
this.start = start;
this.end = end;
if(start<=2 && end >=3) {
count = 1;// 0-3之间的一个已知质数
this.start = 3;
}
}
@Override
public void run() {
// 循环i从[start,end)
for(int i =start;i<end;i++) {
if(isPrime(i)) {
count++;
}
}
}
// 判断一个数字是不是质数
private boolean isPrime(int i) {
double max = 1+Math.sqrt(i);
for(int j = 2;j<max;j++) {
if(i%j==0) {
return false;
}
}
return true;
}
}
}
4.4 练习:setDaemon后台线程
package 线程;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test_setDaemon后台线程 {
public static void main(String[] args) {
T1 t1 = new T1();
t1.start();
// 创建匿名内部类对象
Thread t2 = new Thread() {
@Override
public void run() {
// 在main线程中,打断t1线程的暂停状态
System.out.println("回车打断t1线程");
// 因为t1与main是两个并行的线程,所以,互不影响
// 因此,“等待输入回车”与时间每秒打印互不影响
new Scanner(System.in).nextLine();
t1.interrupt();
}
};
// 设置t2为后台进程,JVM虚拟机不会等待t2进程结束
t2.setDaemon(true);
t2.start();
}
static class T1 extends Thread {
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
for(int i = 0;i<10;i++) {
String s = sdf.format(new Date());
System.out.println("当前时间:" + s);
// 停1秒,因为CPU效率极高,在一秒内可以打印多次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 忽略了该异常,暂不处理
System.out.println("t1进程被打断!");
break;
}
}
}
}
}
本文地址:https://blog.csdn.net/AlieNeny/article/details/113850641
上一篇: JavaScript中两个字符串的匹配
下一篇: python reduce函数
推荐阅读
-
荐 java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!
-
JAVASE 小白学习笔记 (12-3)Java中的常用类--StringBuffer类、StringBuilder类
-
java学习笔记(基础篇)—集合
-
【Java学习】多线程1
-
《深入理解java虚拟机》学习笔记--第三章:垃圾收集器与内存分配策略 jvm
-
《深入理解java虚拟机》学习笔记--第四章:虚拟机性能监控与故障处理工具 虚拟机java
-
《深入理解java虚拟机》学习笔记--第四章:虚拟机性能监控与故障处理工具 虚拟机java
-
《深入理解java虚拟机》学习笔记--第三章:垃圾收集器与内存分配策略 jvm
-
Python 爬虫学习笔记之多线程爬虫
-
Python 爬虫学习笔记之单线程爬虫