Java-多线程和同步
我有两个非常相似的程序,每个程序都试图运行两个线程OddThread和EvenThread,并试图按顺序打印奇数和偶数。第一个有效,第二个挂起。有人能指出第二个程序中的错误吗 第一个有效的方法是:Java-多线程和同步,java,multithreading,synchronization,wait,notify,Java,Multithreading,Synchronization,Wait,Notify,我有两个非常相似的程序,每个程序都试图运行两个线程OddThread和EvenThread,并试图按顺序打印奇数和偶数。第一个有效,第二个挂起。有人能指出第二个程序中的错误吗 第一个有效的方法是: public class ThreadTest { public static void main(String[] args) { System.out.println("Odd Even test"); NumHolder objNumHolder = new NumHolder
public class ThreadTest {
public static void main(String[] args) {
System.out.println("Odd Even test");
NumHolder objNumHolder = new NumHolder();
Odd o1 = new Odd(objNumHolder, "Odd Number Thread");
Even e1 = new Even(objNumHolder, "Even Number Thread");
o1.start();
e1.start();
}
}
class NumHolder {
private int intCurrNum;
private boolean isEven = false;
public synchronized void printOddNumber(String tname) {
while (isEven == true){
try {
wait();
}catch (InterruptedException e) {
}
}
isEven = true;
System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
intCurrNum += 1;
notifyAll();
}
public synchronized void printEvenNumber(String tname) {
while (isEven == false) {
try {
wait();
} catch (InterruptedException e) {
}
}
isEven = false;
System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
intCurrNum += 1;
notifyAll();
}
}
class Even extends Thread {
private NumHolder objNumHolder;
public Even(NumHolder p_objNumHolder, String name) {
super(name);
objNumHolder=p_objNumHolder;
}
public void run() {
for (int i = 0; i < 10; i++) {
objNumHolder.printEvenNumber(getName());
}
}
}
class Odd extends Thread {
private NumHolder objNumHolder;
public Odd(NumHolder p_objNumHolder,String name) {
super(name);
objNumHolder = p_objNumHolder;
}
public void run() {
for (int i = 0; i < 10; i++) {
objNumHolder.printOddNumber(getName());
}
}
}
公共类线程测试{
公共静态void main(字符串[]args){
System.out.println(“奇偶测试”);
NumHolder objNumHolder=新NumHolder();
奇数o1=新奇数(objNumHolder,“奇数螺纹”);
偶数e1=新偶数(objNumHolder,“偶数螺纹”);
o1.start();
e1.start();
}
}
类NumHolder{
私有int intCurrNum;
私有布尔值isEven=false;
公共同步的void printOddNumber(字符串tname){
while(isEven==true){
试一试{
等待();
}捕捉(中断异常e){
}
}
isEven=真;
System.out.println(“线程名称=“+tname+”==Number=“+intCurrNum”);
intCurrNum+=1;
notifyAll();
}
公共同步的void printEvenNumber(字符串tname){
while(isEven==false){
试一试{
等待();
}捕捉(中断异常e){
}
}
isEven=假;
System.out.println(“线程名称=“+tname+”==Number=“+intCurrNum”);
intCurrNum+=1;
notifyAll();
}
}
类甚至扩展了线程{
私人NumHolder objNumHolder;
公共偶数(NumHolder p_objNumHolder,字符串名称){
超级(姓名);
objNumHolder=p_objNumHolder;
}
公开募捐{
对于(int i=0;i<10;i++){
printEvenNumber(getName());
}
}
}
类奇数扩展线程{
私人NumHolder objNumHolder;
公共奇数(NumHolder p_objNumHolder,字符串名称){
超级(姓名);
objNumHolder=p_objNumHolder;
}
公开募捐{
对于(int i=0;i<10;i++){
printOddNumber(getName());
}
}
}
挂起的第二个代码:
class PrintClass {
int intCurrNum;
private boolean isEven = false;
synchronized void printOdd(){
while(isEven){
try{
wait();
}catch(InterruptedException ie){
System.out.println("Interrupted exception in printOdd()");
ie.printStackTrace();
}
isEven = true;
System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
intCurrNum += 1;
notifyAll();
}
}
synchronized void printEven(){
while(!isEven){
try{
wait();
}catch(InterruptedException ie){
System.out.println("Interrupted exception in printEven()");
ie.printStackTrace();
}
isEven = false;
System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
intCurrNum += 1;
notifyAll();
}
}
}
class ThreadOdd extends Thread {
PrintClass pc = null;
ThreadOdd(PrintClass pc , String name){
super(name);
this.pc = pc;
}
public void run(){
for (int i = 0; i < 10; i++) {
pc.printOdd();
}
}
}
class ThreadEven extends Thread {
PrintClass pc = null;
ThreadEven(PrintClass pc,String name){
super(name);
this.pc = pc;
}
public void run(){
for (int i = 0; i < 10; i++) {
pc.printEven();
}
}
}
public class EvenOddPrintClass {
public static void main(String[] args){
PrintClass pc = new PrintClass();
Thread to = new ThreadOdd(pc,"ThreadOdd");
Thread te = new ThreadEven(pc,"ThreadEven");
to.start();
te.start();
}
}
class打印类{
int intCurrNum;
私有布尔值isEven=false;
同步的void printOdd(){
while(isEven){
试一试{
等待();
}捕获(中断异常ie){
System.out.println(“printOdd()中的中断异常”);
即printStackTrace();
}
isEven=真;
System.out.println(“线程名称=“+Thread.currentThread().getName()+”==Number=“+intCurrNum”);
intCurrNum+=1;
notifyAll();
}
}
同步的void print偶数(){
而(!isEven){
试一试{
等待();
}捕获(中断异常ie){
System.out.println(“print偶数()中的中断异常”);
即printStackTrace();
}
isEven=假;
System.out.println(“线程名称=“+Thread.currentThread().getName()+”==Number=“+intCurrNum”);
intCurrNum+=1;
notifyAll();
}
}
}
类ThreadOdd扩展线程{
PrintClass pc=null;
ThreadOdd(PrintClass pc,字符串名称){
超级(姓名);
this.pc=pc;
}
公开募捐{
对于(int i=0;i<10;i++){
pc.printOdd();
}
}
}
类Thread偶而扩展线程{
PrintClass pc=null;
Thread偶数(PrintClass pc,字符串名称){
超级(姓名);
this.pc=pc;
}
公开募捐{
对于(int i=0;i<10;i++){
pc.printfeen();
}
}
}
公共类{
公共静态void main(字符串[]args){
PrintClass pc=新的PrintClass();
螺纹至=新螺纹奇数(pc,“螺纹奇数”);
螺纹te=新的螺纹平衡(pc,“螺纹平衡”);
to.start();
te.start();
}
}
谢谢。很有趣。因此,最初的
isEven=false
。如果先调用printOdd()
,则while(isEven)
测试为false,因此printOdd()
将立即退出,而不生成任何输出。第一个程序中的while
循环仅包含wait
测试,而不是整个方法
然后,当另一个线程调用print偶数()
时,它将调用wait()
并挂起,因为没有其他线程可以调用notifyAll()
您应该只需要
while
循环wait
,因为在打印出偶数或奇数后您将退出,对吗?因此,第一个程序中的逻辑是正确的。在两个版本中,isEven都以false开头
在第一个版本中,printOddNumber将跳过整个,而循环,打印奇数,将IsEvent设置为true并通知偶数线程,该线程将按顺序打印偶数并再次通知奇数线程等
在第二个版本中,printOddNumber将跳过整个循环,包括打印数字和通知偶数线程。在10次尝试后,它将在没有打印任何内容的情况下退出,并在没有通知它的情况下使线程挂起。我建议您在调试器中运行代码并逐步完成这两个线程。这很有教育意义。您将看到错误的确切位置。这与作业有关吗?如果一个线程处于“挂起”状态,可能是因为第一个线程锁定了第二个线程试图锁定的资源;或者,它可能在等待信号,但线程一从未发出信号。我们需要知道wait
函数中的内容,否则很难判断。@Lirik:这是java.lang.Object中的wait方法。另一个线程一直在等待另一个线程在printOdd/print偶数方法末尾使用notifyAll调用唤醒它,但它们可能会在方法同步时卡住,或者另一个线程从while循环中失败,而另一个线程被卡住等待():in for The notify。@esaj。。。哦,明白了。我忘了!很抱歉,我不想将sleep()用于此目的。
public class CountDownApp
{
public static void main(String[] args)
{
Thread count1 = new CountDownEven();
Thread count2 = new CountDownOdd();
count1.start();
count2.start();
}
}
class CountDownEven extends Thread
{
public void run()
{
for(int i=10;i>0;i-=2)
{
System.out.print(+i+"-");
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class CountDownOdd extends Thread
{
public void run()
{
for(int i=9;i>0;i-=2)
{
System.out.print(+i+"-");
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}