Java 线程的基本使用
创建线程
创建线程的方式有两种:
- 继承
thread
类 - 实现
runnable
接口
thread
类实现了 runnable
接口。使用继承 thread
类的方式创建线程时,最大的局限是不支持多继承。所以为了支持多继承,应该使用实现 runnable
接口的方式。两种方式创建的线程在工作时是一样的,没有本质区别。
第一种方式,继承 thread
类并重写 run()
方法:
public class work extends thread { @override public void run() { system.out.println("working..."); } } public class run { public static void main(string[] args) { work work = new work(); work.start(); system.out.println("end!"); } }
运行结果可能 “end!”先输出。在使用多线程时,运行结果与调用顺序是无关的。
调用
run()
方法只是普通的方法调用,不会启动线程。如果多次调用start()
方法,会抛出illegalthreadstateexception
异常。
第二种方式,实现 runnable
接口:
public class work implements runnable { @override public void run() { system.out.println("working..."); } } public class run { public static void main(string[] args) { thread t = new thread(new work()); t.start(); system.out.println("end!"); } }
这种方式与第一种在运行上没有什么区别。其优点在于突破了单继承的限制。
thread 类的部分构造方法:
构造方法 | 说明 |
---|---|
thread() | 创建一个新的线程 |
thread(string name) | 创建一个新的线程,并指定名称 |
thread(runnable target) | 创建一个新的线程,将 target 作为运行对象 |
thread(runnable target, string name) | 将 target 作为运行对象,并指定名称 |
thread(threadgroup group, runnable target) | 将 target 作为运行对象,并作为线程组的一员 |
线程的方法
currentthread() 方法
currentthread()
方法返回正在被执行的线程的信息。
public class run() { public static void main(string[] args) { system.out.println(thread.currentthread().getname()); } }
以上代码在控制台输出 “main“,说明该方法被名为 main 的线程调用。
import static java.lang.system.out; public class run { static class work extends thread { @override public void run() { out.printf("%s 被调用\n", currentthread().getname()); } } public static void main(string[] args) { work t1 = new work(), t2 = new work(); t1.start(); t2.start(); } }
以上代码运行结果:
thread-0 被调用 thread-1 被调用 process finished with exit code 0
在
run()
方法中可以省略thread
直接调用currentthread()
方法。
isalive() 方法
该方法判断当前线程是否处于活动状态。
import static java.lang.system.out; public class run { static class work extends thread { @override public void run() { out.printf("运行中 %s\n", isalive()); } } public static void main(string[] args) throws throwable { work t = new work(); out.printf("运行前: %s\n", t.isalive()); t.start(); // 等待线程运行完成 thread.sleep(1000); out.printf("运行结束: %s\n", t.isalive()); } }
以上代码运行结果:
运行前: false 运行中 true 运行结束: false process finished with exit code 0
sleep() 方法
sleep()
方法指定毫秒数让当前线程休眠(暂停运行),该操作不会释放锁。
停止线程
interrupt() 方法
interrupt()
方法并不能立刻停止线程,只是在在线程中打了一个停止的标记。
import static java.lang.system.out; public class stopthread { static class work extends thread { @override public void run() { for (int i = 1; i <= 50000; i++) { out.printf("i = %d\n", i); } } } public static void main(string[] args) throws throwable { work work = new work(); work.start(); thread.sleep(200); work.interrupt(); out.println("call interrupt!"); } }
以上代码运行结果:
... i = 8190 i = 8191 i = 8192 call interrupt! i = 8193 i = 8194 i = 8195 ...
interrupt()
方法调用后,线程仍在运行。
要使用 interrupt()
方法停止线程,需要在线程中判断中断状态,有两个方法:
-
interrupted()
:测试当前线程是否是中断状态,执行后将状态清除,设置为false
; -
isinterrupted()
:作用同上,但是不清除状态。
import static java.lang.system.out; public class stopthread { static class work extends thread { @override public void run() { for (int i = 1; i <= 50000; i++) { if (isinterrupted()) { out.println("跳出循环!"); break; } out.printf("i = %d\n", i); } } } public static void main(string[] args) throws throwable { work work = new work(); work.start(); thread.sleep(200); work.interrupt(); out.println("call interrupt!"); } }
以上代码执行结果:
... i = 8301 i = 8302 i = 8303 i = 8304 i = 8305 i = 8306 i = 8307 call interrupt! 跳出循环! process finished with exit code 0
在调用 interrupt()
方法后,循环已经退出。但是这种方式只是跳出了循环,假如 for 循环外还有代码,仍然会执行。
抛出异常停止线程
可以在判断线程状态为中断时,抛出一个异常,在 catch
或 finally
块中做中断后的处理:
import static java.lang.system.out; public class stopthread { static class work extends thread { @override public void run() { try { for (int i = 1; i <= 50000; i++) { if (isinterrupted()) { out.println("interrupted!"); throw new interruptedexception("抛出异常!"); } out.printf("i = %d\n", i); } out.println("for 循环结束!"); } catch (interruptedexception e) { out.println(e.getmessage()); } } } public static void main(string[] args) throws throwable { work work = new work(); work.start(); thread.sleep(200); work.interrupt(); out.println("call interrupt!"); } }
以上代码将线程要执行的任务放入 try
块中,当判断为中断状态时,抛出 interruptedexception
,如果需要释放锁,可以在 finally
块中执行。
也可以配合 return
来停止线程:
if (isinterrupted()) { return; }
暂停线程
java 提供了 和 suspend()
方法来暂停和恢复线程,不过这两个方法已经过期作废了。resume()
suspend()
方法暂停线程时,不会释放锁。所以使用 suspend()
方法容易产生死锁。
如果需要暂停线程,可以加入一个标记,若标记指出线程需要暂停,使用 wait()
进入等待状态,如需要恢复,使用 notify()
唤醒。
import static java.lang.system.out; public class stopthread { static class work extends thread { // 暂停标记 private boolean issuspended = false; void pause() { issuspended = true; } synchronized void wake() { issuspended = false; // 唤醒 this.notify(); out.println("已唤醒!"); } @override public void run() { synchronized (this) { try { for (int i = 1; i <= 5000; i++) { if (isinterrupted()) { return; } if (issuspended) { out.println("已暂停!"); // 等待 this.wait(); } out.printf("%s i = %d\n", getname(), i); } out.printf("%s end!\n", getname()); } catch (interruptedexception e) { out.println(e.getmessage()); } } } } public static void main(string[] args) throws throwable { work work = new work(); work.start(); thread.sleep(100); // 暂停 work.pause(); thread.sleep(100); // 唤醒 work.wake(); } }
以上代码使用 wait()
和 notify()
暂停与恢复线程。运行结果:
... thread-0 i = 202 thread-0 i = 203 thread-0 i = 204 已暂停! 已唤醒! thread-0 i = 205 thread-0 i = 206 thread-0 i = 207 ... thread-0 i = 4998 thread-0 i = 4999 thread-0 i = 5000 thread-0 end! process finished with exit code 0
yield 方法
yield()
方法的作用是放弃当前的 cpu 资源,让其他的任务去占用 cpu 执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得时间片。
import static java.lang.system.currenttimemillis; import static java.lang.system.out; public class yield { static class work extends thread { @override public void run() { long before = currenttimemillis(); int sum = 0; for (int i =1; i < 2000000; i++) { // yield(); sum += (i + 1); } long after = currenttimemillis(); out.printf("cost: %dms\n", after - before); } } public static void main(string[] args) { new work().start(); } }
以上代码不使用 yield()
方法时大概 15ms 执行完,加上后大概有 500ms。
推荐阅读