线程应用
示例1
公司年会 进入公司有两个门(前门和后门)
进门的时候 每位人都能获取一张彩票(7位数)
公司有100个员工
利用多线程模拟进门过程
统计每个入口入场的人数
每个人拿到的彩票的号码 要求7位数字 不能重复
打印格式:
编号为: 1 的员工 从后门 入场! 拿到的双色球彩票号码是: [17, 24, 29, 30, 31, 32, 07]
编号为: 2 的员工 从后门 入场! 拿到的双色球彩票号码是: [06, 11, 14, 22, 29, 32, 15]
.....
从后门 入场的员工总共: 45 位员工
从前门 入场的员工总共: 55 位员工
package com.lanou3g;
import java.awt.List;
import java.util.ArrayList;
public class Demo01 {
public static void main(String[] args) {
YHRunnable runnable = new YHRunnable();
Thread t1 = new Thread(runnable, "前门");
Thread t2 = new Thread(runnable, "后门");
t1.start();
t2.start();
}
}
class YHRunnable implements Runnable{
private int pNum = 100;
private int qNym = 0;
private int hNum = 0;
@Override
public void run() {
while(true) {
synchronized (this) {
if(pNum <= 0) {
break;
}
String name = Thread.currentThread().getName();
if(name.equals("前门")) {
qNym++;
System.out.print("编号为:" + (100 - pNum + 1) +
"从" + name + "入场!" + "拿到的双号球彩票号码是:");
printCP();
pNum--;
}
if(name.equals("后门")) {
hNum++;
System.out.print("编号为:" + (100 - pNum + 1) +
"从" + name + "入场!" + "拿到的双号球彩票号码是:");
printCP();
pNum--;
}
if(pNum == 0) {
System.out.println("从前门" + "入场的员工总数:" +qNym);
System.out.println("从后门" + "入场的员工总数:" +hNum);
}
}
Thread.yield();
}
}
public void printCP() {
ArrayList<Integer> list = new ArrayList<>();
while(list.size() < 7) {
int num = (int)(Math.random()*(30 - 1 + 1) + 1);
if(!list.contains(num)) {
list.add(num);
}
}
System.out.println(list);
}
}
需要一份共享的数据,实现两个线程同时使用这份数据,因此只能创建一个对象,由两个线程共享,如果有两份数据
由两个线程分别使用,则将毫无意义,先分析清楚需要哪些步骤,后编写代码
停止线程
停止线程:只要线程停了就叫停止线程
具体有两种实现方式
一种是使用bool标记的方式
另一种是使用interrupt中断线程
测试结果:interrupt是不能结束字子线程的
实际上这个interrupt()方法
设置了isInterrupted 布尔值
如果线程中有wait()等待 或者 sleep休眠
这时调用interrupt()方法
会抛出一个异常IntterruptedException
并且清楚中断状态
如果线程中没有等待或者休眠
这时调用interrupt方法
会设置中断状态(true/false的改变)
中断了线程
package com.lanou3g;
public class Demo20 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("线程已经中断了");
System.out.println(Thread.currentThread().getName());
System.out.println("主线程结束了");
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
long millis = System.currentTimeMillis();
while (System.currentTimeMillis() - millis < 1000) {
}
System.out.println(Thread.currentThread().getName());
}
}
}
未中断线程
package com.lanou3g;
public class Demo21 {
public static void main(String[] args) {
MyRunnable3 myRunnable3 = new MyRunnable3();
Thread thread = new Thread(myRunnable3);
thread.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("线程已经终止了");
System.out.println(Thread.currentThread().getName());
System.out.println("主线程已经停止");
}
}
class MyRunnable3 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方法 尽量不要使用
如果要停止线程 直接使用标记法
只有遇到了 冷冻状态时 可以使用该方法
IllegalMonitorStateException
对象监视器 就是对象锁
wait方法是Object类
wait方法必须使用锁对象去调用
线程等待 放弃了cup的执行资源
package com.lanou3g;
public class Demo23 {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
for (int i = 0; i < 50; i++) {
if(i == 25) {
t1.interrupt();
t2.interrupt();
}
System.out.println(i + "------ ");
}
System.out.println("主线程结束");
}
}
class MyThread extends Thread{
@Override
public synchronized void run() {
while(true) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " ");
}
}
}
线程1进来了 带着锁 遇到wait()方法
放弃了cpu的执行权 但是锁会还回去
线程2进来了 又遇到了等待了
相当于我的两个线程 都跟这里等着了
进入冷冻(中断)状态
解除冷冻(中断)状态
调用interrupt清楚该状态
代码示例
package com.lanou3g;
public class Demo06 {
public static void main(String[] args) {
Person person = new Person();
SetRunnable setRunnable = new SetRunnable(person);
Thread thread1 = new Thread(setRunnable);
PrintRunnable printRunnable = new PrintRunnable(person);
Thread thread2 = new Thread(printRunnable);
thread1.start();
thread2.start();
}
}
class SetRunnable implements Runnable {
private Person person;
private boolean isTrue = true;
public SetRunnable() {
super();
}
public SetRunnable(Person person) {
super();
this.person = person;
}
@Override
public void run() {
while (true) {
synchronized (person) {
if (person.flag == true) {
try {
person.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (isTrue) {
person.name = "张三";
person.gender = "男";
} else {
person.name = "zhangsan";
person.gender = "nv";
}
isTrue = !isTrue;
person.flag = true;
person.notify();
}
}
}
}
class PrintRunnable implements Runnable {
private Person person;
public PrintRunnable() {
super();
}
public PrintRunnable(Person person) {
super();
this.person = person;
}
@Override
public void run() {
while (true) {
synchronized (person) {
if (person.flag == false) {
try {
person.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(person);
person.flag = false;
person.notify();
}
}
}
}
class Person {
public String name;
public String gender;
public boolean flag = false;
@Override
public String toString() {
return "姓名:" + name + "\n年龄:" + gender;
}
}