目录
Thread类
一、有关线程名的一些方法
调用**Thread.currentThread().getName()**可以查看当前线程的名字。
1.Thread.currentThread().getName()方法
未做设置时,主线程叫做main,其他线程是Thread-x。
代码示例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);
Thread t2 = new Thread(myThread);
Thread t3 = new Thread(myThread);
t1.start();
t2.start();
t3.start();
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
main
Thread-0
Thread-1
Thread-2
2.public Thread(Runnable target,String name)构造方法
给线程起名字用public Thread(Runnable target,String name)构造方法
代码示例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread,"zy");
Thread t2 = new Thread(myThread,"zyy");
Thread t3 = new Thread(myThread,"zyyy");
t1.start();
t2.start();
t3.start();
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
main
zyy
zyyy
zy
此处打印结果表明:
代码的运行结果与代码执行顺序或调用顺序是无关的
3.setName()
调用setName()方法时,要先调用checkAccess()方法,查看是否有修改此线程的权限,如果有,则继续调用setName(),没有权限则出现SecurityException异常。
代码示例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread,"zy");
Thread t2 = new Thread(myThread,"zyy");
Thread t3 = new Thread(myThread,"zyyy");
t1.start();
t2.start();
t3.start();
t1.setName("z");
t2.setName("y");
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
main
z
y
zyyy
二、守护线程
守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。
创建守护线程时,方法和普通线程一样,只是在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程。
注意:
- 在线程启动前设置为守护线程,⽅法是setDaemon(boolean on)。
- 使⽤守护线程不要访问共享资源(数据库、⽂件等),例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失。
- 守护线程中产⽣的新线程也是守护线程。
代码示例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread,"zy");
Thread t2 = new Thread(myThread,"zyy");
t2.setDaemon(true);
t1.start();
t2.start();
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
main
zy
上⾯的代码运⾏多次可以出现(电脑性能⾜够好的同学可能测试不出来):线程1和主线程执⾏完了,我们的守护线程2就不执⾏了。
三、线程的优先级
设定优先级的方法是:Thread.setPriority(int n) // 1~10, 默认值5。
优先级高的线程被操作系统调度的优先级较高,操作系统对高优先级线程可能调度更频繁,但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。
四、线程的生命周期
1.sleep()方法
调⽤sleep⽅法会进⼊计时等待状态,等时间到了,进⼊的是就绪状态⽽并⾮是运⾏状态。
代码示例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread,"zy");
Thread t2 = new Thread(myThread,"zyy");
t1.start();
try {
t1.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
zy
main
zyy
//t1执行后暂停2秒后继续执行其他线程。
2.线程的让步:yield()⽅法
调⽤yield⽅法会先让别的线程执⾏,但是不确保真正让出。
代码示例:
public class ThreadYield {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
while (Thread.activeCount() > 1){ //Thread.activeCount()获取当前所在线程组的活跃线程数
Thread.yield();
}
System.out.println(Thread.currentThread().getName());
}
}
程序未能终止,一致处于等待状态,只打印出Thread-0。
3.线程的等待:join()方法
代码示例一:
public class Test{
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
thread.start();
thread.join();
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
Thread-0
main
thread.join();等待thread线程执行完毕,故现打印Thread-0
代码示例二:
public class Test{
public static void main(String[] args) throws InterruptedException{
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.join(2000);
System.out.println(Thread.currentThread().getName());
}
}
打印结果:
main
Thread-0
t线程执行之间为2秒,Thread.sleep(5000)为5秒,5秒>2秒,故时间一过2秒,就往下执行,故先打印main线程。
4.线程的中断
1.interrupt()方法
注意:interrupt不会真正停止⼀个线程,它仅仅是设置了⼀个中断标志,给这个线程发了⼀个信号告诉它,它应该要结束了。
2.静态方法interrupted()
会清除中断标志位
3.实例⽅法isInterrupted()
不会清除中断标志位
对目标线程调用interrupt()方法可以请求中断一个线程,目标线程通过检测isInterrupted()标志获取自身是否已中断。如果目标线程处于等待状态,该线程会捕获到InterruptedException。
目标线程检测到isInterrupted()为true或者捕获了InterruptedException都应该立刻结束自身线程。
public class Test{
public static void test() throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i<5;i++){
System.out.println(i+"="+Thread.currentThread().isInterrupted());
}
//线程运行状态时,需要自行判断线程中断标志位,处理中断操作
//阻塞状态时,通过捕获及处理异常,来中断线程的中断逻辑
while (!Thread.interrupted()){
System.out.println(Thread.currentThread().getName());
}
}
});
t.start();//t线程的中断标志位=false
t.interrupt();//t线程的中断标志位=true
}
public static void main(String[] args) throws InterruptedException {
test();
}
}
打印结果:
0=true
1=true
2=true
3=true
4=true
因为t线程的中断标志位变为true。
public class Test{
public static void test() throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().isInterrupted());
//线程调用wait()/join()/sleep()阻塞时,如果把当前线程给中断,会直接抛一个异常
//抛出异常以后,线程中断标志位会重置
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().isInterrupted());
}
}
});
t.start();//t线程的中断标志位=false
t.interrupt();//t线程的中断标志位=true
}
public static void main(String[] args) throws InterruptedException {
test();
}
}
打印结果:
true
false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lesson3.InterruptThread$3.run(InterruptThread.java:50)
at java.lang.Thread.run(Thread.java:748)
public class Test{
public static volatile boolean IS_INTERRUPTED;
//使用自定义的中断标志位
public static void test(){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
//自定义的标志位能满足线程处于运行态的中断操作
while (IS_INTERRUPTED){
System.out.println(Thread.currentThread().getName());
}
//自定义的标志位满足不了线程处于阻塞状态时的中断操作
try {
Thread.sleep(999999);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
IS_INTERRUPTED = true;
}
public static void main(String[] args) throws InterruptedException {
test();
}
}
无限循环打印Thread-0。原因见注释。