停止线程
停止线程:只要线程停了就叫做停止线程
使用boolean标记方法中断线程:
class StopRunnable implements Runnable{
public boolean isOver = false;
@Override
public void run() {
while (!isOver) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public class Demo01 {
public static void main(String[] args) throws InterruptedException {
StopRunnable sr = new StopRunnable();
Thread t1 = new Thread(sr);
t1.start();
Thread.sleep(3000);
sr.isOver = true;
System.out.println("停止线程");
Thread.sleep(1000);
System.out.println("主线程结束");
}
}
测试interrupt中断线程:
public class Demo {
public static void main(String[] args) throws InterruptedException {
StopRunnable sr = new StopRunnable();
Thread t1 = new Thread(sr);
t1.start();
Thread.sleep(3000);
t1.interrupt();
System.out.println("停止线程");
Thread.sleep(1000);
System.out.println("主线程结束");
}
}
class StopRunnable implements Runnable{
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
测试结果:
实际上interrupt()这个方法设置了isInterrupted布尔值,如果不测试线程是否中断,子线程不会中断
如果线程中有wait()等待或者sleep()休眠
这时调用interrupt方法会抛出一个异常InterruptedException并且清除中断状态,子程序继续运行;
如果线程中没有等待或者休眠
这时调用interrupt方法会设置中断状态(也就是true/false的改变)
测试中断状态
public class Demo {
public static void main(String[] args) {
InterruptThread t1 = new InterruptThread();
InterruptThread t2 = new InterruptThread();
t1.start();
t2.start();
for (int i = 0; i < 50; i++) {
if (i == 25) {
t1.isOver = true;
break;
}
System.out.println(i + "----");
}
System.out.println("主线程结束");
}
}
class InterruptThread extends Thread{
public boolean isOver = false;
@Override
public synchronized void run() {
while (!isOver) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "run");
}
}
}
测试结果:线程1进来带着锁遇到wait方法放弃了CPU的执行资源,但是锁会还回去
紧接着线程2拿着锁进来,又遇到wait方法,也放弃了CPU的执行资源,相当于两个线程进入冷冻(中断)状态
注意:如果在非同步方法里调用wait方法,会出现IllegalMonitorStateException异常(对象监视器就是对象锁)
所以在调用wait方法必须拥有对象锁
public class Demo {
public static void main(String[] args) {
InterruptThread t1 = new InterruptThread();
InterruptThread t2 = new InterruptThread();
t1.start();
t2.start();
for (int i = 0; i < 50; i++) {
if (i == 25) {
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(i + "----");
}
System.out.println("主线程结束");
}
}
class InterruptThread extends Thread{
@Override
public synchronized void run() {
while (true) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "run");
}
}
}
测试结果:
调用interrupt方法可以消除该状态,但是碰到wait方法会抛出异常,所以建议进来不要使用interrupt方法
如果要停止线程直接使用标记法来停止,只有遇到了等待状态时,可以使用该方法强行清除该等待状态
间隔输出
需求:
Person类 姓名 性别
开启两个线程
一个对Person对象进行赋值
一个对Person对象进行打印
一次打印 张三 男
一次打印 zahngsan nv
间隔输出
分析:
1.先保证要操作都是同一个对象
2.要保证数据安全需要使用锁并且要使用同一把锁
3.保证操作的逻辑顺序要对(先赋值 再打印)用 wait 和 notify
class Person {
public String name;
public String gender;
public boolean flag = false;
}
class SetRunnable implements Runnable{
private Person p;
private boolean isTrue = true;
public SetRunnable() {
super();
}
public SetRunnable(Person p) {
super();
this.p = p;
}
@Override
public void run() {
while (true) {
synchronized (p) {
if (p.flag == true) {
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (isTrue) {
p.name = "张三";
p.gender = "男";
} else {
p.name = "zhangsan";
p.gender = "nv";
}
isTrue = !isTrue;
p.flag = true;
p.notify();
}
}
}
}
class PrintRunnable implements Runnable{
private Person p;
public PrintRunnable() {
super();
}
public PrintRunnable(Person p) {
super();
this.p = p;
}
@Override
public void run() {
while(true) {
synchronized (p) {
if (p.flag == false) {
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(p.name + "---" + p.gender);
p.flag = false;
p.notify();
}
}
}
}
public class Demo06 {
public static void main(String[] args) {
Person person = new Person();
SetRunnable sr = new SetRunnable(person);
Thread t1 = new Thread(sr);
t1.start();
PrintRunnable pr = new PrintRunnable(person);
Thread t2 = new Thread(pr);
t2.start();
}
}
间隔输出逻辑:
赋值线程需要赋值完毕,打印线程才能去打印
打印线程需要打印完毕,赋值线程才能去赋值
赋值的时候打印线程在等待,等赋值完成后才能去打印打印完成后通知赋值线程继续赋值
实现间隔输出:
使用一个标记完成切换wait() 和 notify(),实现上面的逻辑
两个线程必须保证使用同一个标记,所以标记要声明在Person类中
代码优化:把之前上锁的代码封装到类中,从同步代码块封装成同步方法
修改部分代码如下(未改同上):
class Person {
public synchronized void setPerson(String name, String gender) {
if (flag == true) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
this.gender = gender;
flag = true;
this.notify();
}
public synchronized void printPerson() {
if (flag == false) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "---" + gender);
flag = false;
this.notify();
}
}
class PrintRunnable implements Runnable{
@Override
public void run() {
while(true) {
p.printPerson();
}
}
}
class SetRunnable implements Runnable{
@Override
public void run() {
while (true) {
if (isTrue) {
p.setPerson("张三", "男");
} else {
p.setPerson("zhangsan", "nv");
}
isTrue = !isTrue;
}
}
}