线程的暂停和恢复:即让线程暂时停止运行,并能恢复
suspend() 暂停线程。为已经过时方法
resume() 恢复暂停的线程。为已经过时的方法
例子
public class SuspendThread extends Thread{
private int i;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
@Override
public void run() {
super.run();
while (true) {
i++;
}
}
}
SuspendThread thread = new SuspendThread();
thread.start();
Thread.sleep(1000);
System.out.println(thread.getI());
Thread.sleep(1000);
thread.suspend(); //线程暂停
System.out.println(thread.getI());
Thread.sleep(1000);
System.out.println(thread.getI());
thread.resume(); //线程恢复
thread.sleep(1000);
System.out.println(thread.getI());
运行结果:
502839629
1079189339
1079189339 //线程暂停到恢复期间线程停止执行,i值不变
1721670999
这两个方法的缺点:
如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象
如某个线程在同步的代码中暂停了,而没有恢复,则同步锁被永远占用。
这两个方法本身是不同步的,易造成数据不同步的情况
如:
public class SuspendThread extends Thread{
private int i;
private int j;
public void setValue(int i, int j){
this.i = i;
Thread.currentThread().suspend(); //线程启动后设置了i值后暂停,由于不同步,此时这个对象被其他线程访问则出现数据不一致问题
this.j = j;
};
@Override
public void run() {
setValue(122, 333);
}
}
SuspendThread thread = new SuspendThread();
thread.start();
Thread.sleep(100);
System.out.println(thread.getI() + " " + thread.getJ()); //主线程获取到了子线程修改的成员变量
运行结果 : 122 0
yield()方法,为Thread的静态方法,作用是放弃当前cpu资源,将它让给其他任务去执行,当放弃的时间不确定。 可能刚放弃马上又获得cpu时间片
public class YieldThread extends Thread{
private int i;
@Override
public void run() {
long begin = System.currentTimeMillis();
for (int k = 0; k < 50000000; k++) {
i += k;
}
long end = System.currentTimeMillis();
System.out.println("不执行Thread.yield();时执行时间为:" + (end - begin) + "毫秒");
long begin2 = System.currentTimeMillis();
for (int k = 0; k < 50000000; k++) {
Thread.yield(); //没次循环调用此方法
i += k;
}
long end2 = System.currentTimeMillis();
System.out.println("执行Thread.yield();时执行时间为:" + (end2 - begin2) + "毫秒");
}
}
YieldThread thread = new YieldThread();
thread.start();
执行结果:
不执行Thread.yield();时执行时间为:16毫秒
执行Thread.yield();时执行时间为:24541毫秒
线程优先级:
在操作系统中,线程可以划分优先级,优先级较高的线程得到的cpu资源较多,cpu有限执行优先级较高的线程对象中的任务
1.设置线程优先级的方法:
setPriority();
2.优先级分为1-10 这10个等级,小于1或大于10将抛出 IllegalArgumentException异常
YieldThread thread1 = new YieldThread();
thread1.setName("优先级10的线程");
thread1.setPriority(10);
thread1.start();
YieldThread thread2 = new YieldThread();
thread2.setName("优先级1的线程");
thread2.setPriority(1);
thread2.start();
运行结果:
优先级10的线程的线程执行时间为:171毫秒 //优先级高的执行快 //注意这里执行快不是因为这个线程先被main启动,与调用顺序无关
优先级1的线程的线程执行时间为:296毫秒
3.线程的优先级具有继承性:即A线程启动了B线程,则B线程的优先级和A相同
如:
System.out.println("main线程优先级:" + Thread.currentThread().getPriority());
YieldThread thread = new YieldThread();
thread.start(); //主线程启动thread线程
System.out.println(thread.getName() + "线程优先级:" + thread.getPriority());
运行结果:
main线程优先级:5
Thread-0线程优先级:5 //继承了main线程的优先级
4.优先级具有随机性:
不能说优先级高就一定执行的更快,具有随机性,即大部分情况下优先级高的执行的快,是个概率问题
守护线程:
java线程分为两种:用户线程和守护线程
守护线程是一种特殊的线程:又陪伴的含义,守护线程是为其他线程的运行提供便利服务的。
jvm示例中只要有非守护线程没有结束,守护线程就不会结束。只有当所有的非守护线程结束时,守护线程才会结束销毁
典型的守护线程:GC(垃圾回收器)
例子:
public class DaemonThread extends Thread{
private int i;
@Override
public void run() {
while (true) {
try {
System.out.println(i++);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
try {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true); //设置线程为守护线程
daemonThread.start();
Thread.sleep(5000);
System.out.println("main主线程要结束了。守护线程将不再打印了,也会结束");
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
0
1
2
3
4
main主线程要结束了。守护线程将不再打印了,也会结束 //主线程结束后,守护线程跟着结束