当前位置: 代码迷 >> J2SE >> 请问多线程同步有关问题,多谢了
  详细解决方案

请问多线程同步有关问题,多谢了

热度:28   发布时间:2016-04-23 19:37:57.0
请教多线程同步问题,谢谢了!
本帖最后由 yazhi1992 于 2015-09-13 03:14:48 编辑
先贴代码
package HomeWork911;

public class Test2 {
//要求:制作两个线程对象,要求用同步块的方式使第一个线程运行2次,然后将自己阻塞起来,唤醒
//第二个线程,第二个线程再运行2次,然后将自己阻塞起来,唤醒第一个线程……两个线程交替执行。
public static void main(String[] args) {
Print p = new Print(2);
MyThread myThread = new MyThread(p);
new Thread(myThread, "线程1").start(); //开启线程1
new Thread(myThread, "线程2").start(); //开启线程2
}

}

class MyThread implements Runnable{
Print p;

public MyThread(Print p) {
super();
this.p = p;
}

@Override
public synchronized void run() {
for (int i = 0; i < 100; i++) { //让run方法重复100次
p.print1(); 

}
}

}

class Print {
int num;
int j = -1; //

public Print(int num) {
this.num = num;
}

public synchronized void print1() {
if(j < 0) { //*1 : 让第一个抢到CPU资源的进程休眠
j++;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while(j % num == 0) { //每个进程运行两次就进入阻塞状态
if(j == 0) { //*2 :任何数对0求余都等0,所以加入这个判断使一开始j==0可以执行下去
break;
}
try {
this.notify();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
j++; //执行一次自加1,达到每两次就进入阻塞状态并唤醒别人的效果
System.out.println(Thread.currentThread().getName() + "运行"); //执行一次就输出一次
}
}


要求是两个线程,线程1执行两次后阻塞自己,唤醒线程2,2再执行两次后阻塞自己,唤醒1,以此类推。我的想法是,定一个线程1、2公用的参数j,j初始值=-1.程序开始时,线程1、线程2谁先抢到CPU资源,谁就先休眠,不执行任何操作。(*1 : 让第一个抢到CPU资源的进程休眠),因为我对线程同步的理解是,如果没加入*1这个条件,有可能1执行了一次后,还没执行第二次,CPU资源就被2抢走,2开始执行,所以加个判断条件,先抢到的让他阻塞,好让对方去一次性执行两次。不知道我这个理解有没有错?为什么程序运行起来没有反应,1或2一次都没执行。是我哪里理解有误吗?
求指导,谢谢!
------解决思路----------------------
什么输出都没有的原因在于你synchronized修饰了run方法和print1方法,然后你在wait的时候只释放了print1上的锁(也就是加在Print对象上的锁),而没有释放加在MyThread对象上的锁,使得另一个线程无法获得MyThread上的锁(被等待的线程持有中),自然也就无法进入print1方法,造成了死锁。

关于*1:这段代码在synchronized方法中,意味着同一时刻只有一个线程处于方法中,因此不用担心被另一个线程抢去执行(这也是synchronized块的一个基本用法)。
关于*2:感觉逻辑怪怪的。。要是我的话就弄一个计数输出两次以后就把执行权让给另一个线程。
------解决思路----------------------
public class Test2 {
public static void main(String[] args) {
        Print1 p = new Print1();
        MyThread1 myThread = new MyThread1(p);
        new Thread(myThread, "线程1").start(); //开启线程1
        new Thread(myThread, "线程2").start(); //开启线程2 
  }
}

class MyThread1 implements Runnable {
private Print1 p;

public MyThread1(Print1 p) {
this.p = p;
}

@Override
public void run() {
        while(true){
         p.method();
        }
}

}

class Print1 {
private Object obj = new Object();

public void method() {
synchronized (obj) {
obj.notifyAll();
for(int i = 0;i < 2;i++){
System.out.println(Thread.currentThread().getName() + " is doing something!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

------解决思路----------------------
在你的程序里,你同步了run方法,就是说通过MyThread开启的线程是互斥的,在主程序中运行,其中1个线程拿到了锁,另外一个线程就阻塞了。
在拿到锁的线程中执行 p.print1(),这里又拿到了p锁,此时j<0,wait放弃了p锁,此时线程还掌握这前面一个锁,所以死锁。

如果你把run方法的同步去掉就会发现,执行完2次还是进行了死锁,因为当j=2的时候无论哪个线程都会执行
try {
                this.notify();
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
这个语句,唤醒->休眠循环
------解决思路----------------------
那就看你要同步的地方是哪了

同步run方法,整个run方法体都是同步块

同步print方法,print方法的方法体是同步块

------解决思路----------------------
引用:
public class Test2 {
public static void main(String[] args) {
        Print1 p = new Print1();
        MyThread1 myThread = new MyThread1(p);
        new Thread(myThread, "线程1").start(); //开启线程1
        new Thread(myThread, "线程2").start(); //开启线程2 
  }
}

class MyThread1 implements Runnable {
private Print1 p;

public MyThread1(Print1 p) {
this.p = p;
}

@Override
public void run() {
        while(true){
         p.method();
        }
}

}

class Print1 {
private Object obj = new Object();

public void method() {
synchronized (obj) {
obj.notifyAll();
for(int i = 0;i < 2;i++){
System.out.println(Thread.currentThread().getName() + " is doing something!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这里面为什么要用Thread.sleep(1000);   到底是为什么
------解决思路----------------------
这里的Thread.sleep(1000)模拟现实情况下,执行真实的任务需要1s。
  相关解决方案