在Java中,我们有两种方式创建线程:
实现功能:创建和运行9个线程。每个线程能计算和输出1~9以内的乘法。
使用继承Thread类覆盖run方法:
public class ThreadDemo extends Thread {
private int number;
public ThreadDemo(int number){
super();
this.number = number;
}
@Override
public void run() {
for (int i = 1; i < 10; i++) {
System.out.printf("%s: %d * %d = %d\n",
Thread.currentThread().getName(), number, i, i * number);
}
}
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
ThreadDemo threadDemo = new ThreadDemo(i);
threadDemo.start();
}
}
}
实现Runnable的run方法:
public class RunnableDemo implements Runnable{
private int number;
public Calculator(int number){
this.number = number;
}
@Override
public void run() {
for (int i = 1; i < 10; i++) {
System.out.printf("%s: %d * %d = %d\n",
Thread.currentThread().getName(), number, i, i * number);
}
}
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
RunnableDemo runnableDemo = new RunnableDemo(i);
Thread thread = new Thread(runnableDemo);
thread.start();
}
}
}
总结
每个Java程序最少有一个执行线程。当你运行程序的时候, JVM运行负责调用main()方法的执行线程。
当调用Thread对象的start()方法时, 我们创建了另一个执行线程。在这些start()方法调出后,我们的程序就有了多个执行线程。
当全部的线程执行结束时(更具体点,所有非守护线程结束时),Java程序就结束了。如果初始线程(执行main()方法的主线程)运行结束,其他的线程还是会继续执行直到执行完成。但是如果某个线程调用System.exit()指示终结程序,那么全部的线程都会结束执行。
创建一个Thread类的对象不会创建新的执行线程。同样,调用实现Runnable接口的 run()方法也不会创建一个新的执行线程。只有调用start()方法才能创建一个新的执行线程。
推荐使用Runnable来实现线程。
原因:在Java中我们继承时,只能继承一个类,而引入的接口可以有多个。
Thread类的对象中保存了一些属性信息能够帮助我们来辨别每一个线程,知道它的状态,调整控制其优先级。 这些属性是:
实现功能:开发一个为10个线程设置名字和优先级的程序,然后展示它们的状态信息直到线程结束。这些线程会计算数字乘法表。
public class ThreadDemo {
private static final int TEN = 10;
public static void main(String[] args) {
//创建一个大小为10的Thread类的数组和一个大小为10的Thread.State数组来保存将要执行的线程和它们的状态。
Thread[] threads = new Thread[TEN];
Thread.State[] status = new Thread.State[TEN];
//创建10个Calculator类的对象,每个初始为不同的数字,然后分别用10个线程来运行它们。把其中5个的优先值设为最高,把另外5个的优先值为最低。
for (int i = 0; i < TEN; i++) {
threads[i] = new Thread(new Calculator(i));
if (i % 2 == 0) {
threads[i].setPriority(Thread.MAX_PRIORITY);
} else {
threads[i].setPriority(Thread.MIN_PRIORITY);
}
threads[i].setName("Thread " + i);
}
//创建一个 PrintWriter对象用于把线程状态的改变写入文档。
try (FileWriter file = new FileWriter("C:\\Thead-Runnable.log");
PrintWriter printWriter = new PrintWriter(file)) {
//把10个线程的状态写入文档。现在,它成为NEW.
for (int i = 0; i < TEN; i++) {
printWriter.println("Main : Status of Thread " + i + " : " + threads[i].getState());
status[i] = threads[i].getState();
}
//开始执行这10个线程
for (int i = 0; i < TEN; i++) {
threads[i].start();
}
//直到这10个线程执行结束,我们会一直检查它们的状态。如果发现它的状态改变,就把状态记入文本。
boolean finish = false;
while (!finish) {
for (int i = 0; i < TEN; i++) {
if (threads[i].getState() != status[i]) {
writeThreadInfo(printWriter, threads[i], status[i]);
status[i] = threads[i].getState();
}
}
finish = true;
for (int i = 0; i < TEN; i++) {
finish = finish && (threads[i].getState() == Thread.State.TERMINATED);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void writeThreadInfo(PrintWriter pw, Thread thread, Thread.State state) {
pw.printf("Main : Id %d - %s\n", thread.getId(), thread.getName());
pw.printf("Main : Priority: %d\n", thread.getPriority());
pw.printf("Main : Old State: %s\n", state);
pw.printf("Main : New State: %s\n", thread.getState());
pw.printf("Main : ************************************\n");
}
}
总结
程序的控制台显示的是线程计算的乘法表,而Thead-Runnable.log文本记录的是不同线程的状态演变。
Thread 类有能保存使用线程信息的属性。JVM根据线程的优先级来选择将使用CPU的线程,然后再根据每个线程的情况来实现它们的状态。
如果你没有声明一个线程的名字,那么JVM会自动命名它为:Thread-XX,XX是一个数字。线程的ID或者状态是不可修改的。Thread类没有实现setId()和setStatus()方法来允许修改它们。
学习内容:
如何使用Thread对象来访问线程的属性信息。
也可以实现Runnable接口来访问这些信息。
也可以用Thread类的静态方法currentThread()来访问正在运行的Runnable 对象的 Thread对象。
注:setPriority() 方法会抛出 IllegalArgumentException 异常,如果你设置的优先级不是在1-10之间。
一个多个线程在执行的Java程序,只有当其全部的线程执行结束时(更具体的说,是所有非守护线程结束或者某个线程调用System.exit()方法的时候),它才会结束运行。有时,你需要为了终止程序而结束一个线程,或者当程序的用户想要取消某个Thread对象正在做的任务。
Java提供中断机制来通知线程表明我们想要结束它。中断机制的特性是线程需要检查是否被中断,而且还可以决定是否响应结束的请求。所以,线程可以忽略中断请求并且继续运行。
实现功能:开发一个程序,它创建线程,然后在5秒之后,它会使用中断机制来强制结束线程。
创建PrimeGenerator:
public class PrimeGenerator extends Thread {
@Override
public void run() {
long number = 1L;
while (true) {
if (isPrime(number)) {
System.out.printf("Number %d is Prime", number);
}
//检测线程是否中断
//如果继承Runnable,使用静态方法“Thread.interrupted()”来判断线程是否中断。
if (isInterrupted()){
System.out.println("\nThe Prime Generator has been Interrupted");
return;
}
number++;
}
}
private boolean isPrime(long number) {
if (number <= 2) {
return true;
}
for (long i = 2; i < number; i++) {
if ((number % i) == 0) {
return false;
}
}
return true;
}
}
创建main方法:
public class ThreadDemo {
public static void main(String[] args) {
Thread task = new PrimeGenerator();
task.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//中断线程
task.interrupt();
}
}
总结
isInterrupted() 方法和Thread.interrupted() 静态方法有着很重要的区别。
Thread.interrupted()静态方法调用后,线程会取消中断状态,而isInterrupted()方法不会,建议使用isInterrupted()方法,非常重要!
在之前,学习了如何中断执行线程和如何对Thread对象的中断控制。
但是如果线程实现的是由复杂的算法分成的一些方法,或者它的方法有递归调用,那么我们可以用更好的机制来控制线程中断。
为了这个Java提供了InterruptedException异常。当你检测到程序的中断并在run()方法内捕获,你可以抛这个异常。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。