1. 线程
1.1创建线程
创建线程通常有以下三种方式:
实现Runnable接口,并重写其run方法:
public class J1_Method01 {
public static void main(String[]args) {
System.out.println("Main线程的ID为:" +Thread.currentThread().getId());
Threadthread= new Thread(new CustomRunner());
thread.start();
}
}
class CustomRunner implements Runnable {
@Override
public void run() {
System.out.println("CustomRunner线程的ID为:" +Thread.currentThread().getId());
}
}
继承自Thread类,并重写其run方法:
public class J2_Method02 {
public static void main(String[]args) {
System.out.println("Main线程的ID为:" +Thread.currentThread().getId());
CustomThreadcustomThread= new CustomT服务器托管网hread();
customThread.start();
}
}
class CustomThread extends Thread {
@Override
public void run() {
System.out.println("CustomThread线程的ID为:" +Thread.currentThread().getId());
}
}
以上两种方式都无法获取线程的返回值,如果想要获取线程的返回值,需要实现Callable接口:
public class J3_Method03 {
public static void main(String[]args)throwsExecutionException,InterruptedException{
Tasktask= new Task();
FutureTaskInteger>futureTask= new FutureTask(task);
new Thread(futureTask).start();
System.out.println("获得线程返回值:" +futureTask.get());
}
}
class Task implements Callable {
@Override
publicIntegercall() {
return 100;
}
}
//输出:
获得线程返回值:100
1.2线程属性
编号(ID):用于标识线程的唯一编号,只读属性。
名称(Name):用于定义线程名称,可读可写。
线程类别(Daemon):通过线程的`setDaemon(booleanon)`方法进行设置,为true表示设置为守护线程,否则为用户线程。用户线程会阻止Java虚拟机正常停止,守护线程则不会。通常可以把一些不重要的线程设置为守护线程,比如监控其他线程状态的监控线程,当其他工作线程停止后,虚拟机就可以正常退出。
优先级(Priority):Java线程支持1到10十个优先级,默认值为5。Java线程的优先级本质上只是给线程调度器一个提示信息,它并不能保证线程一定按照优先级的高低顺序运行,所以它是不可靠的,需要谨慎使用。在Java平台中,子线程的优先级默认与其父线程相同。
1.3线程状态
Java线程的生命周期分为以下五类状态:
RUNABLE:该状态包括两个子状态:READY和RUNING。处于READY状态的线程被称为活跃线程,被线程调度器选中后才开始运行,转化为RUNING状态。
BLOCKED:一个线程发起一个阻塞式IO操作后(如文件读写或者阻塞式Socket读写),或者申请一个由其他线程持有的独占资源(比如锁)时,相应的线程就会处于该状态。
WAITING:线程处于无时间限制的等待状态。
TIMED_WAITING:有时间限制的等待状态,如果在指定时间内并没有执行的特定的操作,则该线程自动转换为RUNABLE。
TERMINATED:`Thread.run()`正常返回或者由于抛出异常而提前终止,则对应的线程都会处于该终止状态。
各个状态之间的转换关系如下图:
1.4线程终止
通常线程会随着代码的运行完成而终止,但如果你在线程中进行了死循环操作,此时就需要考虑如何安全地停止线程?虽然Thread类提供了`stop()`方法,但其已经被标识为废弃,因为`stop()`只是暴力的停止线程,但此时线程中的操作仍可能处于中间状态,此时暴力地停止就可能会产生非预期的结果。想要安全的停止线程,可以通过改变终止标志位的方式来实现:
public class ThreadStop {
private staticvolatilebooleanstopFlag= true;
public static void main(String[]args)throwsInterruptedException{
Threadthread= new Thread(() -> {
while (stopFlag) {
try {
Thread.sleep(100);
System.out.println("持续输出");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
});
thread.start();
Thread.sleep(3 * 1000);
stopFlag= false;
System.out.println("线程终止");
}
}
1.5线程中断
除了终止线程外,JDK中提供了以下方法用于实现线程中断:
Thread.interrupt():用于给目标线程设置中断标志位,但实际上并不能中断线程;
Thread.isInterrupted():通过检查中断标志位,判断当前线程是否被中断;
Thread.interrupted():用来判断当前线程的中断状态,同时会清除当前线程的中断标志位。
线程中断与线程终止的区别在于:线程中断只是告诉目标线程,我希望你停止运行,即设置标志位,而线程是否真的停止则是由其自行决定。示例如下:
/**
*interrupt()只是设置中断标志位,并不能中断线程,所以子线程会持续打印
*/
public class J1_Interrupt {
public static void main(String[]args)throwsInterruptedException{
Threadthread= new Thread(() -> {
while (true) {
System.out.println("子线程打印");
}
});
thread.start();
Thread.sleep(10);
thread.interrupt();
}
}
/**
*isInterrupted()用于检查当前线程是否存在中断标志位,配合interrupt()使用可以中断线程
*/
public class J2_IsInterrupted {
public static void main(String[]args)throwsInterruptedException{
Threadthread= new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("子线程打印");
}
});
thread.start();
Thread.sleep(10);
thread.interrupt();
}
}
/**
*interrupted()用于判断当前线程的中断状态,并清除当前线程的中断标志位
*/
public class J3_Interrupted {
public static void main(String[]args)throwsInterruptedException{
Threadthread= new Thread(() -> {
//此时由于标志位被清除,此时子线程依然会持续打印
while (!Thread.interrupted() || !Thread.currentThread().isInterrupted()) {
System.out.println("子线程打印");
}
});
thread.start();
Thread.sleep(10);
thread.interrupt();
}
}
2. 基本概念
2.1变量分类
状态变量(StateVariable):即类的实例变量,非共享的静态变量。
共享变量(SharedVariable):即可以被多个线程共同访问的变量。
2.2竞态
如果多个线程并发的操作共享变量,并且这些操作不全是只读操作,那么它们彼此之间就会存在竞争,这种状态就称为竞态。由于竞态的存在,此时可能存在一个类在单线程的环境下能够正常运转,但在多线程的环境下却运行出错,此时就称这个类是线程不安全的。
public class J1_ThreadUnsafe {
private staticinti= 0;
public static void main(String[]args)throwsInterruptedException{
IncreaseTasktask= new IncreaseTask();
Threadthread1= new Thread(task);
Threadthread2= new Thread(task);
thread1.start();
thread2.start();
//等待线程结束再打印返回值
thread1.join();
thread2.join();
System.out.println(i); //线程不安全,输出总是小于:200000
}
static class IncreaseTask implements Runnable {
@Override
public void run() {
for (intj= 0;j 100000;j++) {
inc();
}
}
pr服务器托管网ivate void inc() {
i++;
}
}
}
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
目录 一、中文乱码 二、chardet.detect()解决 三、在页面查找编码格式解决 一、中文乱码 问题在于文本的编码格式不正确 import requests url=’https://www.shicimingju.com/book/sanguoyan…