Java多线程基础知识篇

这篇是Java多线程基本用法的一个总结。

本篇文章会从一下几个方面来说明Java多线程的基本用法:

  1. 如何使用多线程
  2. 如何得到多线程的一些信息
  3. 如何停止线程
  4. 如何暂停线程
  5. 线程的一些其他用法

所有的代码均可以在char01

如何使用多线程

启动线程的两种方式

run
public class ExampleThread extends Thread{
@Override
public void run() {
super.run();
System.out.println("这是一个继承自Thread的ExampleThread");
}
}
ExampleThreadTest
public class ExampleRunable  implements Runnable{
public void run() {
System.out.println("这是实现Runnable接口的类");
}
}
ExampleRunableTest

如何得到多线程的一些信息

我们在启动多线程之后,希望能通过一些API得到启动的线程的一些信息。JDK给我们提供了一个Thread类的方法来得到线程的一些信息。

getName()getId()isAlive()

得到线程的名字

Thread.currentThread()Thread.currentThread()
public class ExampleCurrentThread extends Thread{
public ExampleCurrentThread(){
System.out.println("构造方法的打印:" + Thread.currentThread().getName());
} @Override
public void run() {
super.run();
System.out.println("run方法的打印:" + Thread.currentThread().getName());
}
}

测试的代码如下:

public class ExampleCurrentThreadTest extends TestCase {
public void testInit() throws Exception{
ExampleCurrentThread thread = new ExampleCurrentThread();
} public void testRun() throws Exception {
ExampleCurrentThread thread = new ExampleCurrentThread();
thread.start();
Thread.sleep(1000);
}
}

结果如下:

构造方法的打印:main
run方法的打印:Thread-0
构造方法的打印:main
ExampleCurrentThreadThread.currentThread()Thread.currentThread()
public class ComplexCurrentThread extends Thread{
public ComplexCurrentThread() {
System.out.println("begin=========");
System.out.println("Thread.currentThread().getName=" + Thread.currentThread().getName()); System.out.println("this.getName()=" + this.getName());
System.out.println("end===========");
} @Override
public void run() {
super.run();
System.out.println("run begin=======");
System.out.println("Thread.currentThread().getName=" + Thread.currentThread().getName());
System.out.println("this.getName()=" + this.getName());
System.out.println("run end==========");
}
}

测试代码如下:

public class ComplexCurrentThreadTest extends TestCase {
public void testRun() throws Exception {
ComplexCurrentThread thread = new ComplexCurrentThread();
thread.setName("byhieg");
thread.start(); Thread.sleep(3000);
}
}

结果如下:

begin=========
Thread.currentThread().getName=main
this.getName()=Thread-0
end===========
run begin=======
Thread.currentThread().getName=byhieg
this.getName()=byhieg
run end==========
Thread.currentThread()ComplexCurrentThreadThread.currentThread()Thread.currentThread()

得到线程的ID

ExampleIdThreadExampleIdThreadTest

判断线程是否存活

方法isAlive()的作用是测试线程是否处于活动状态。所谓活动状态,就是线程已经启动但是没有终止。即该线程start之后,被认为是存活的。

我们看一下具体的例子:

public class AliveThread extends Thread{
@Override
public void run() {
super.run();
System.out.println("run方法中是否存活" + " " + Thread.currentThread().isAlive());
}
}

测试方法如下:

public class AliveThreadTest extends TestCase {
public void testRun() throws Exception {
AliveThread thread = new AliveThread();
System.out.println("begin == " + thread.isAlive());
thread.start();
Thread.sleep(1000);
System.out.println("end ==" + thread.isAlive()); Thread.sleep(3000);
}
}

结果如下:

begin == false
run方法中是否存活 true
end ==false

我们可以发现在start之前,该线程被认为是没有存活,然后run的时候,是存活的,等run方法执行完,又被认为是不存活的。

如何停止线程

判断线程是否终止

isInterrupted()和interrupted()

停止线程的方式

这个是得到线程信息中比较重要的一个方法了,因为这个和终止线程的方法相关联。先说一下终止线程的几种方式:

  1. 等待run方法执行完
  2. 线程对象调用stop()
  3. 线程对象调用interrupt(),在该线程的run方法中判断是否终止,抛出一个终止异常终止。
  4. 线程对象调用interrupt(),在该线程的run方法中判断是否终止,以return语句结束。

第一种就不说了,第二种stop()方法已经废弃了,因为可能会产生如下原因:

StopLockThreadStopLockThreadTest
interrupted()isInterrupted()interrupted()isInterrupted()
public class ExampleInterruptThread extends Thread{
@Override
public void run() {
super.run();
try{
for(int i = 0 ; i < 50000000 ; i++){
if (interrupted()){
System.out.println("已经是停止状态,我要退出了");
throw new InterruptedException("停止.......");
}
System.out.println("i=" + (i + 1));
}
}catch (InterruptedException e){
System.out.println("顺利停止");
} }
}

测试的代码如下:

public class ExampleInterruptThreadTest extends TestCase {
public void testRun() throws Exception {
ExampleInterruptThread thread = new ExampleInterruptThread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
InterruptedException

如何暂停线程

在JDK中提供了以下两个方法用来暂停线程和恢复线程。

  • suspend()——暂停线程
  • resume()——恢复线程

这两个方法和stop方法一样是被废弃的方法,其用法和stop一样,暴力的暂停线程和恢复线程。这两个方法之所以是废弃的主要由以下两个原因:

  1. 线程持有锁定的公共资源的情况下,一旦被暂停,则公共资源无法被其他线程所持有。
  2. 线程强制暂停,导致该线程执行的操作没有执行完全,这时访问该线程的数据会出现数据不一致。

线程的一些其他用法

线程的其他的一些基础用法如下:

  1. 线程让步
  2. 设置线程的优先级
  3. 守护线程

线程让步

ExampleYieldThreadExampleYieldThreadTest

设置线程的优先级

我们可以设置线程的优先级来让CPU尽可能的将执行的资源给优先级高的线程。Java设置了1-10这10个优先级,又有三个静态变量来提供三个优先级:

    /**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1; /**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5; /**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;

我们可以通过setPriority来设置线程的优先级,可以直接传入上诉三个静态变量,也可以直接传入1-10的数字。设置后线程就会有不同的优先级。如果我们不设置优先级,会是什么情况?

线程的优先级是有继承的特性,如果我们在A线程中启动了B线程,则AB具有相同的优先级。一般我们在main线程中启动线程,就和main线程有一致的优先级。main线程的优先级默认是5。

下面说一下优先级的一些规则:

  1. 优先级高的线程一般会比优先级低的线程获得更多的CPU资源,但是不代表优先级高的任务一定先于优先级低的任务先执行完。因为不同优先级的线程中run方法内容可能不一样。
  2. 优先级高的线程一定会比优先级低的线程执行的快。如果两个线程是一样的run方法,但是优先级不一样,确实优先级高的线程先执行完。

线程守护

ExampleDaemonThreadExampleDaemonThreadTest

总结

这篇文章主要总结了Java线程的一些基本的用法,关于线程安全,同步的知识,放到了第二篇。