多线程的概念是相对于顺序编程 而言的,在顺序编程里,程序只能按照一条线进行执行,而多线程可以打破这一限制,实现并发 效果。
多线程的基本实现方式
继承Thread类
通过继承Thread类可以实现新的线程,这样会很简便,但一般来说,是不被建议这样使用的。
它最大的缺陷是,一旦继承了Thread类就无法继承别的类,对设计造成一定的影响。
以下的demo中,我们通过继承Thread类来实现多线程。
共开启5个线程,线程名字分别初始化为1到5的数字。每个线程开始执行后,均是每隔一秒输出一次当前状态。
class InheritThread extends Thread {
private int waitSeconds = 5;
private static int threadCount = 0;
public InheritThread() {
super(Integer.toString(threadCount++));
}
public void run() {
while (waitSeconds > 0) {
System.out.print(this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitSeconds--;
}
}
//override toString method
public String toString() {
String name = getName();
String info = "InheritThread:" + name + ", current waitSeconds = " + waitSeconds + "\n";
return info;
}
}
public class TestClass {
public static void main(String[] args) {
Thread thread;
for (int i = 0; i < 5; i++) {
thread = new InheritThread();
thread.start();
}
}
}
输出结果:(对于多线程问题,不同机器和平台上,同样的代码也可能产生不同的结果)
InheritThread:1, current waitSeconds = 5
InheritThread:2, current waitSeconds = 5
InheritThread:3, current waitSeconds = 5
InheritThread:4, current waitSeconds = 5
InheritThread:5, current waitSeconds = 5
InheritThread:1, current waitSeconds = 4
InheritThread:2, current waitSeconds = 4
InheritThread:3, current waitSeconds = 4
InheritThread:4, current waitSeconds = 4
InheritThread:5, current waitSeconds = 4
InheritThread:1, current waitSeconds = 3
InheritThread:2, current waitSeconds = 3
InheritThread:3, current waitSeconds = 3
InheritThread:4, current waitSeconds = 3
InheritThread:5, current waitSeconds = 3
InheritThread:1, current waitSeconds = 2
InheritThread:3, current waitSeconds = 2
InheritThread:2, current waitSeconds = 2
InheritThread:4, current waitSeconds = 2
InheritThread:5, current waitSeconds = 2
InheritThread:1, current waitSeconds = 1
InheritThread:2, current waitSeconds = 1
InheritThread:3, current waitSeconds = 1
InheritThread:4, current waitSeconds = 1
InheritThread:5, current waitSeconds = 1
实现Runnable接口
Runnable是JDK里的一个接口,我们可以把它理解为一个 "任务“, 即是我们要用它实现的线程执行的任务。
Thread类本身就是实现了Runnable接口的,所以我们才可以直接继承Thread类实现线程。
同样,我们只需实现Runnable接口(复写它的 run 方法), 就可以用它来实现线程。
以下的例子所做的操作和上个例子基本是一样的:
class ImpRunnable implements Runnable {
private int waitSeconds = 5;
private static int threadCount = 0;
private final int myThreadCount = threadCount;
public ImpRunnable() {
threadCount++;
}
public void run() {
while (waitSeconds > 0) {
System.out.print(this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitSeconds--;
}
}
//override toString method
public String toString() {
String name = "ImplRunnabeThread:" + myThreadCount;
String info = name + ", current waitSeconds = " + waitSeconds + "\n";
return info;
}
}
public class TestClass {
public static void main(String[] args) {
Thread thread;
for (int i = 0; i < 5; i++) {
thread = new Thread(new ImpRunnable());
thread.start();
}
}
}
输出结果:
ImplRunnabeThread:0, current waitSeconds = 5
ImplRunnabeThread:1, current waitSeconds = 5
ImplRunnabeThread:2, current waitSeconds = 5
ImplRunnabeThread:3, current waitSeconds = 5
ImplRunnabeThread:4, current waitSeconds = 5
ImplRunnabeThread:0, current waitSeconds = 4
ImplRunnabeThread:1, current waitSeconds = 4
ImplRunnabeThread:2, current waitSeconds = 4
ImplRunnabeThread:3, current waitSeconds = 4
ImplRunnabeThread:4, current waitSeconds = 4
ImplRunnabeThread:0, current waitSeconds = 3
ImplRunnabeThread:1, current waitSeconds = 3
ImplRunnabeThread:2, current waitSeconds = 3
ImplRunnabeThread:3, current waitSeconds = 3
ImplRunnabeThread:4, current waitSeconds = 3
ImplRunnabeThread:0, current waitSeconds = 2
ImplRunnabeThread:1, current waitSeconds = 2
ImplRunnabeThread:2, current waitSeconds = 2
ImplRunnabeThread:3, current waitSeconds = 2
ImplRunnabeThread:4, current waitSeconds = 2
ImplRunnabeThread:0, current waitSeconds = 1
ImplRunnabeThread:1, current waitSeconds = 1
ImplRunnabeThread:2, current waitSeconds = 1
ImplRunnabeThread:3, current waitSeconds = 1
ImplRunnabeThread:4, current waitSeconds = 1
几种常用的线程操作
休眠
可以通过 Thread.sleep( millseconds )方法使线程终止执行给定的时间。
(以上两个demo中均使用了该方法)
注意使用该方法时需要捕获 InterruptedException.
让步
系统在实现多线程时,其实是对cpu的使用时间进行了切分,通过策略分别分配给各个线程cpu的使用机会。
如果我们在实现线程时,某些时间段不需要使用cpu,那么我们可以通过 Thread.yield() 方法通知线程调度器: 我现在暂时不需要cpu了,让别的线程使用吧。
但是要注意:这仅仅是一个暗示或者提示,没有任何机制能够保证系统会分配给其他线程cpu使用。所以不要完全依赖于 yield 来调度多线程的执行。
设置优先级
初始化一个线程后,它会按照默认的优先级运行。但我们也可以认为设置线程的优先级。
cpu调度器会倾向于让优先级高的线程先执行,但并不是说低优先级的线程不被执行,只是执行的频率会相对低一些。
可以通过 getPriority()方法获取当前线程的优先级,通过setPriority()方法设置优先级。