主函数部分:
public class Demo {
public static void main(String[] args) {
//创建打印数字类的对象
PrintNum pn = new PrintNum();
//以pn为参数创建三个线程
//分别命名为1号、2号、3号
Thread t1 = new Thread(pn, "1号");
Thread t2 = new Thread(pn, "2号");
Thread t3 = new Thread(pn, "3号");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
PrintNum类部分:
public class PrintNum implements Runnable {
//num表示第n个数
private int num = 1;
//state用来作为某一线程是否需要wait的标志
private String state = "1号";
//N用来选择线程1还是线程2还是线程3
int N = 1;
public int getN() {
return N;
}
public void setN(int n) {
N = n;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public void run() {
while (true) {
if(this.num<=60) {
if (getN() == 1) {
printnum1();
setN(2);
} else if (getN() == 2) {
printnum2();
setN(3);
} else if (getN() == 3) {
printnum3();
setN(1);
}
}else{
break;
}
}
}
//线程1的内容
public synchronized void printnum1() {
if(!(getState().equals("1号"))){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//将状态设置为线程2
setState("2号");
//唤醒线程
notifyAll();
}
//线程2的内容
public synchronized void printnum2(){
if(!(getState().equals("2号"))){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//将状态设置为线程3
setState("3号");
//唤醒线程
notifyAll();
}
//线程3的内容
public synchronized void printnum3(){
if(!(getState().equals("3号"))){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//将状态设置为线程1
setState("1号");
//唤醒线程
notifyAll();
}
}
1号线程:1
1号线程:2
1号线程:3
1号线程:4
1号线程:5
1号线程:6
1号线程:7
1号线程:8
1号线程:9
1号线程:10
1号线程:11
1号线程:12
1号线程:13
1号线程:14
1号线程:15
1号线程:16
1号线程:17
1号线程:18
1号线程:19
1号线程:20
1号线程:21
1号线程:22
1号线程:23
1号线程:24
1号线程:25
1号线程:26
1号线程:27
1号线程:28
1号线程:29
1号线程:30
1号线程:31
1号线程:32
1号线程:33
1号线程:34
1号线程:35
1号线程:36
1号线程:37
1号线程:38
1号线程:39
1号线程:40
1号线程:41
1号线程:42
1号线程:43
1号线程:44
1号线程:45
1号线程:46
1号线程:47
1号线程:48
1号线程:49
1号线程:50
1号线程:51
1号线程:52
1号线程:53
1号线程:54
1号线程:55
1号线程:56
1号线程:57
1号线程:58
1号线程:59
1号线程:60
结果输出的全是线程一的1-60,而且没有使进程停止。
我的理解是:
一开始因为有int N = 1;所以run()里执行的是 if (getN() == 1) 的代码块,
里面则是调用的同步方法快printnum1(),因为是线程t1先开始所以应该由它抢到执行权,
当完成前5个打印语句后,将state改为"2号",N改为2,那么这个while循环应该要重新循环了,并且应该直接去if (getN() == 2)的代码块才对。
此时却仍然是Thread.currentThread().getName()为1号。
因此我第一个疑惑是为什么一直是1个线程在抢执行权,但是其他两个没有动?
而当最后一个for循环结束前应该也会有this.num++的动作才对,这样才可以在run()里执行break语句,可是并没有退出循环。
因此我第二个疑惑是程序没有直接退结束,而是一直处于调试状态的原因究竟是为何呢?
请大神们给一个解决方法的思路,谢谢!
引用题主这句话
当完成前5个打印语句后,将state改为"2号",N改为2,那么这个while循环应该要重新循环了,并且应该直接去if (getN() == 2)的代码块才对。
此时却仍然是Thread.currentThread().getName()为1号。
这是有问题的,当n改为2,也只有1号线程开始第二轮循环,2号和3号线程还阻塞在printnum1方法那刚刚准备从阻塞切换为就绪状态呢,等这两个线程切换为就绪状态,cpu也给了时间片,可以重新抢占锁的时候 线程1已经挨个把60个数打印完了,这当然取决于电脑的运算速度,题主不妨把循环次数调大到几千,这个时候应该就能看到2号和3号线程打印数了,,,
至于第二个问题,实际上你多运行几次可能就能正常退出了,假设有一次上下文切换给力了,在1号线程打印完5个数后,2号侥幸拿到了锁,进入了printnum1方法,但是发现state不是预期值,于是就wait了把锁让了出来 1号和3号再次抢占锁,很不幸1号没抢到(如果1号抢到了锁就会继续打印,因为state的值全是1号线程在改变,所以他但凡抢到锁就能畅通无阻打印),3号抢到了,和2号的结局一样,state不是它想要的,继续wait,此时1号线程在等着抢占锁的队列,而2号刚刚被3号唤醒,正准备跻身1号线程所在队列,相比1号失去先机,1号继续打印,等到1号打印完,再次唤醒他们,这个时候num已经61了,2号3号相继灰溜溜退出printnum1方法,这样就能正常退出方法了,题主说的没有退出方法的时候,多半是2号和3号在1号打印完60个数前根本没获取到锁,等到1号已经退出while循环,2号进入printnum1,然后wait,3号也进入printnum1,继续wait,两个线程就wait在哪了,也没有进程去唤醒他们了,所以持续就永远被这两个线程托在那里了
如果要验证,题主不妨在run方法break前面打印一下,再在printnum1方法第一句打印谁抢到了锁
上述均为个人理解,有误请帮忙勘误哈哈哈
run方法中的getN()和setN()存在并发问题,得同步,不同步printnum1、printnum2和printnum3执行的不可预测,三个线程可能都走到一个printnum1()方法里面,最终死锁
帮你修改了一下代码,满意请采纳,谢谢!
public class 线程Demo {
public static void main(String[] args) {
//创建打印数字类的对象
PrintNum pn = new PrintNum();
//以pn为参数创建三个线程
//分别命名为1号、2号、3号
Thread t1 = new Thread(pn, "1号");
Thread t2 = new Thread(pn, "2号");
Thread t3 = new Thread(pn, "3号");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
class PrintNum implements Runnable {
//num表示第n个数
private int num = 1;
//state用来作为某一线程是否需要wait的标志
private String state = "1号";
//N用来选择线程1还是线程2还是线程3
int N = 1;
public int getN() {
return N;
}
public void setN(int n) {
N = n;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public void run() {
while (true) {
if(this.num<=60) {
if (getN() == 1) {
printnum1();
setN(2);
} else if (getN() == 2) {
printnum2();
setN(3);
} else if (getN() == 3) {
printnum3();
setN(1);
}
}else{
break;
}
}
}
//线程1的内容
public synchronized void printnum1() {
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if(!(getState().equals("1号"))){
try {
//将状态设置为线程2
setState("2号");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//唤醒线程
notifyAll();
}
//线程2的内容
public synchronized void printnum2(){
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if(!(getState().equals("2号"))){
try {
//将状态设置为线程3
setState("3号");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//唤醒线程
notifyAll();
}
//线程3的内容
public synchronized void printnum3(){
int num;
for (num=this.num; this.num <= num + 4; this.num++) {
if(!(getState().equals("3号"))){
try {
//将状态设置为线程1
setState("1号");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (this.num <= 60) {
System.out.println(Thread.currentThread().getName() + "线程:" + this.num);
}
}
//唤醒线程
notifyAll();
}
}
您的问题已经有小伙伴解答了,请点击【采纳】按钮,采纳帮您提供解决思路的答案,给回答的人一些鼓励哦~~
ps:开通问答VIP,享受5次/月 有问必答服务,了解详情↓↓↓
【电脑端】戳>>> https://vip.csdn.net/askvip?utm_source=1146287632
【APP 】 戳>>> https://mall.csdn.net/item/52471?utm_source=1146287632
public class PrintNum implements Runnable{
volatile int count=1;
@Override
public void run() {
while(count>0){
synchronized (this){
Integer i = Integer.valueOf(Thread.currentThread().getName());
if(count/5%3+1==i&&count<=60){
for(int num=1;num<=5;num++){
System.out.println(i+"号线程:"+count++);
}
notifyAll();
}else{
if(count>60){
break;
}
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}