线程的常用方法
Thread t = new Thread();
1. 启动线程 shart()
t.stat(); //启动线程
2. 停止线程
注意:不建议使用stop()和destory()方法(已过时),调用其可能会产生不可预料的结果;
线程停止有两种情况:
-
线程体执行结束时线程结束;
-
人为干预,典型做法是提供一个boolean类型的终止变量,当这个变量置为false,终止线程的运行;
例如:
class Terminal implements Runnable {
//1、加入标识,标记线程体是否可以运行
private boolean flag = true;
private String name;
public Terminal(String name) {
this.name = name;
}
@Override
public void run() {
int i = 0;
//2、关联标识,true运行,false停止运行
while (flag) {
System.out.println(name + "--->" + i++);
}
}
//提供修改标识的方法
public void terminate() {
this.flag = false;
}
}
public class TestTerminal {
public static void main(String[] args) {
Terminal terminal = new Terminal("a");
new Thread(terminal).start();
for (int i = 0;i < 10;i++) {
if (i == 8) {
terminal.terminate();
System.out.println("terminal 终止"); //终止线程terminal
}
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
}
}
运行结果:在main函数里,当i==8时终止了子线程
3. 休眠线程sleep()
这里要注意的有:
- 该方法在哪个线程体中,当前线程类对象阻塞;
- sleep(millis)指定当前线程阻塞的毫秒数;
- 存在异常InerruptedException,因为run()无法抛出异常所以只能用try catch捕获异常;
- sleep时间达到后线程进入就绪状态;
- 每一个对象都会有一个锁,而sleep不会释放锁;
sleep()的应用:
- 可以模拟网络延时
- 倒计时
例1:模拟龟兔赛跑,让兔子每走十步休眠100ms;
public class TestRacer implements Runnable{
private static String winner; // 胜利者
@Override
public void run() {
for (int steps = 1; steps <= 100; steps++) {
//模拟休息
if (Thread.currentThread().getName().equals("rabbit") && steps % 10 == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "-->" + steps);
// 比赛是否结束
boolean flag = gameOver(steps);
if (flag) {
break;
}
}
}
private boolean gameOver(int steps) {
if (winner != null) {
return true;
} else if (steps == 100) {
winner = Thread.currentThread().getName();
System.out.println("winner -->" + winner);
return true;
}
return false;
}
public static void main(String[] args) {
TestRacer racer = new TestRacer();
new Thread(racer,"tortoise").start();
new Thread(racer,"rabbit").start();
}
}
例2:模拟网上购票
class Sell implements Runnable{
private int ticketNum = 0;
@Override
public void run() {
while (true) {
if (ticketNum > 20) {
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ticketNum++);
}
}
}
例3:模拟倒计时
public class TestBlockedSleep01 {
public static void main(String[] args) throws InterruptedException {
Date endTime = new Date(System.currentTimeMillis() + 1000*10); //分:秒
long end = endTime.getTime();
while (true) {
System.out.println(new SimpleDateFormat("mm:ss").format(endTime));
Thread.sleep(1000);
endTime = new Date(endTime.getTime() - 1000);
if (end - 10000 > endTime.getTime()) {
break; //十秒后跳出循环,倒计时结束
}
}
}
public static void test() throws InterruptedException {
int num = 10;
while (true) {
Thread.sleep(1000);
System.out.println(num--);
}
}
}
运行结果:
4. 线程让步yield()
让正在执行的线程停止或让步,让给优先级较高的线程获取CPU的执行权,不一定会让出CPU执行权,取决于操作系统,若等待的线程优先级较低或者当前只有一个线程在执行时,那么当前线程又会立即获取到CPU的执行权
- 礼让线程,让当前正在执行线程暂停
- 不是阻塞线程,而是线程从运行状态转入就绪状态,让CPU重新调度
例1:
class Yield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "start");
Thread.yield(); //线程让步
System.out.println(Thread.currentThread().getName() + "end");
}
}
public class TestYield {
public static void main(String[] args) {
Yield m = new Yield();
new Thread(m,"a").start();
new Thread(m,"b").start();
}
}
一次运行结果:让步成功
例2:主线程中i为2的倍数时,主线程调用yield();
ublic class TestYield02 {
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0;i < 5;i++) {
System.out.println("lambda" + i);
}
}).start();
for (int i = 0;i < 5;i++) {
if (i % 2 == 0) {
Thread.yield();
}
System.out.println("main" + i);
}
}
}
5. 线程加入join()
- 合并线程,其他线程阻塞待此线程执行完成后,再执行其他线程;
例:
public class TestJion {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0;i < 10;i++) {
System.out.println("lambda" + i);
}
});
t.start();
for (int i = 0;i < 10;i++) {
if (i == 4) {
t.join();//插队 main主线程被阻塞
}
System.out.println("main" + i);
}
}
}
结果:主线程阻塞后,子线程结束之后才得以继续执行;