Java多线程小程序错误,求解答
classTestWait{publicstaticvoidmain(String[]args){MyThreadmt=newMyThread();//第一个新进程new...
class TestWait
{
public static void main(String[] args)
{
MyThread mt=new MyThread();
//第一个新进程
new Thread(mt).start();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
}
//第二个新进程
new Thread(mt).start();
}
}
class MyThread implements Runnable
{
MyTest mt=new MyTest();
private boolean firOrSen=true;
public void run()
{
//第一个建立的进程执行这里
if(firOrSen)
{
System.out.println("first");
firOrSen=false;
mt.myNotify();
}
//第二个建立的进程执行这里
else
{System.out.println("second");
mt.myWait();
}
}
}
我发不了完整的程序,不够控件,待会请直接联系我!我发程序 展开
{
public static void main(String[] args)
{
MyThread mt=new MyThread();
//第一个新进程
new Thread(mt).start();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
}
//第二个新进程
new Thread(mt).start();
}
}
class MyThread implements Runnable
{
MyTest mt=new MyTest();
private boolean firOrSen=true;
public void run()
{
//第一个建立的进程执行这里
if(firOrSen)
{
System.out.println("first");
firOrSen=false;
mt.myNotify();
}
//第二个建立的进程执行这里
else
{System.out.println("second");
mt.myWait();
}
}
}
我发不了完整的程序,不够控件,待会请直接联系我!我发程序 展开
1个回答
展开全部
是2L说的和你现在出现的这个错误无关,我想1个时间片对于这个程序来说,是绝对可以把几行代码执行完的,从CPU指令的时间上也可以推出来。从上面可以非常明显的看出来,关键是第一次输出的问题,其实你的多线程代码问题很多,但是在你这个程序里表现不出来。
为了解释一些东西,先解释一些概念。其实你说这个问题如果往深处说就复杂了,只能简单的去说
时间片:CPU对线程的执行,是通过分配时间片来实现的,即每个线程每次运行都有一个时间限制,不能超过这个时间,这个时间的最大程度就是时间片(如果不考虑抢占的问题,时间片是一定的,即每个线程每次都运行一个完整的时间片的时间)
线程调度算法:CPU对线程的调度,是有一个算法来决定调度系统所有线程的先后顺序(这里为了方便解释,我全部认为是核心线程,而不存在用户线程,用户线程是通过进程间接调度的,即CPU并不知道有用户线程存在,而核心线程是CPU直接知道的并且直接调度的)。那算法是怎么样的,历史上有无数种线程调度算法,作为一个程序员,你只能认为是不可知的,即你要保证无论哪个线程先执行,程序都是一致的。这个算法由操作系统决定。
取你的代码的关键部分
SLEEP函数:这个函数到底做了什么,两件事,1放弃时间片立即让操作系统进行下一次调度,2定时让自己变得可以重新调度(你设定的时间内此线程是不可调度的)
Tsleep1 T1= new Tsleep1();
Tsleep2 T2= new Tsleep2();
T1.start();
T2.start();
你的程序里绝对T1会先执行完一次循环,这个基本是肯定的,因为要执行的操作肯定用不了半个时间片就足够了,所以时间片造成的放弃调度的问题基本不太可能(针对你的代码)。所以第一个输出一定是输出0,也确实这样。
try{
sleep(1000);
}
好了,解释输出。
前者关键是下面的
0
This is i=0
This is i=1
1
0
This is i=0
1
This is i=1
在你T1第一次输出0后,调用SLEEP放弃了时间片,这个时候T2运行输出了This is i=0,这个过程不太可能有同步的问题,因为相对1S来说,时间片实在是太短了,而且你执行操作极少,基本保证了是原子的。
关键是第3行开始,现在经过前面的调度,T2进入睡眠了,为什么现在反而T2先比T1先运行,明明是T2在睡眠嘛?原因是,你的两个线程都是用户级线程(一般核心级线程要显示的指明,因为开销过大),这种情况下,CPU是先调度进程,然后进程才决定让谁先运行。在T2睡眠的时候,CPU调度其他进程,等到再次轮到你的进程的时候,T1和T2都已经“醒”了,这个时候操作系统要根据自己的算法去决定,这个算法并不是先进先出的,即使你T1先醒,T2后醒,但是两者没有优先级的区别,操作系统视为平等,可以自由选择调度哪一个。 并且,即使两者都是核心级线程,也可能另外其他程序长期占用了CPU而使得下一次调度的时候对两者的调度发生细微的顺序差异。所以即使你T1先START,T2后START,仍然无法保证以后T1先于T2,需要进行同步。同步使用信号量的方法就足够了。
两个线程共享全局变量i,初始化为0,自己同步就行了,反而效率更高些。别说面相对象就不使用全局变量,同步那绝对在多个线程之间避免不了共享。
伪代码,只是表达意思,同时保证了每次操作是原子的也保证了顺序,虽然2L保证了每次操作的原子性,但是没能够保证顺序,当然,可能是看不出来效果的。
T1执行时首先
while{
if(i==0)
{
i++;
执行你想的操作
sleep(0);//放弃时间片就好了,没必要等那么久
}
else
{
sleep(0);//说明T1完后又再次先于T2被调度了,立即放弃时间片
}
}
对于T2
while{
if(i==1)
{
i--;
执行你想的操作
sleep(0)
}
else
{
sleep(0);//立即放弃时间片
}
}
为了解释一些东西,先解释一些概念。其实你说这个问题如果往深处说就复杂了,只能简单的去说
时间片:CPU对线程的执行,是通过分配时间片来实现的,即每个线程每次运行都有一个时间限制,不能超过这个时间,这个时间的最大程度就是时间片(如果不考虑抢占的问题,时间片是一定的,即每个线程每次都运行一个完整的时间片的时间)
线程调度算法:CPU对线程的调度,是有一个算法来决定调度系统所有线程的先后顺序(这里为了方便解释,我全部认为是核心线程,而不存在用户线程,用户线程是通过进程间接调度的,即CPU并不知道有用户线程存在,而核心线程是CPU直接知道的并且直接调度的)。那算法是怎么样的,历史上有无数种线程调度算法,作为一个程序员,你只能认为是不可知的,即你要保证无论哪个线程先执行,程序都是一致的。这个算法由操作系统决定。
取你的代码的关键部分
SLEEP函数:这个函数到底做了什么,两件事,1放弃时间片立即让操作系统进行下一次调度,2定时让自己变得可以重新调度(你设定的时间内此线程是不可调度的)
Tsleep1 T1= new Tsleep1();
Tsleep2 T2= new Tsleep2();
T1.start();
T2.start();
你的程序里绝对T1会先执行完一次循环,这个基本是肯定的,因为要执行的操作肯定用不了半个时间片就足够了,所以时间片造成的放弃调度的问题基本不太可能(针对你的代码)。所以第一个输出一定是输出0,也确实这样。
try{
sleep(1000);
}
好了,解释输出。
前者关键是下面的
0
This is i=0
This is i=1
1
0
This is i=0
1
This is i=1
在你T1第一次输出0后,调用SLEEP放弃了时间片,这个时候T2运行输出了This is i=0,这个过程不太可能有同步的问题,因为相对1S来说,时间片实在是太短了,而且你执行操作极少,基本保证了是原子的。
关键是第3行开始,现在经过前面的调度,T2进入睡眠了,为什么现在反而T2先比T1先运行,明明是T2在睡眠嘛?原因是,你的两个线程都是用户级线程(一般核心级线程要显示的指明,因为开销过大),这种情况下,CPU是先调度进程,然后进程才决定让谁先运行。在T2睡眠的时候,CPU调度其他进程,等到再次轮到你的进程的时候,T1和T2都已经“醒”了,这个时候操作系统要根据自己的算法去决定,这个算法并不是先进先出的,即使你T1先醒,T2后醒,但是两者没有优先级的区别,操作系统视为平等,可以自由选择调度哪一个。 并且,即使两者都是核心级线程,也可能另外其他程序长期占用了CPU而使得下一次调度的时候对两者的调度发生细微的顺序差异。所以即使你T1先START,T2后START,仍然无法保证以后T1先于T2,需要进行同步。同步使用信号量的方法就足够了。
两个线程共享全局变量i,初始化为0,自己同步就行了,反而效率更高些。别说面相对象就不使用全局变量,同步那绝对在多个线程之间避免不了共享。
伪代码,只是表达意思,同时保证了每次操作是原子的也保证了顺序,虽然2L保证了每次操作的原子性,但是没能够保证顺序,当然,可能是看不出来效果的。
T1执行时首先
while{
if(i==0)
{
i++;
执行你想的操作
sleep(0);//放弃时间片就好了,没必要等那么久
}
else
{
sleep(0);//说明T1完后又再次先于T2被调度了,立即放弃时间片
}
}
对于T2
while{
if(i==1)
{
i--;
执行你想的操作
sleep(0)
}
else
{
sleep(0);//立即放弃时间片
}
}
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询