黑马程序员技术交流社区

标题: 关于多线程中资源共享操作的问题 [打印本页]

作者: 创出一片辉煌    时间: 2012-7-30 22:22
标题: 关于多线程中资源共享操作的问题
复习JAVA,对线程共享同步的感觉还是很抽象
比如我写了如下的代码:
class MyThreadSync implements Runnable{
private int ticket=5;
public void run(){
  for(int i=0;i<100;i++){
   if(ticket>0){
    System.out.println("ticket="+ticket);
    ticket--;
   }
  }
}
}
public class SyncDemo {
public static void main(String args[]){
  MyThreadSync mt=new MyThreadSync();
  Thread t1=new Thread(mt);
  Thread t2=new Thread(mt);
  Thread t3=new Thread(mt);
  t1.start();
  t2.start();
  t3.start();
}
}
此时运行的结果为:
ticket=5
ticket=4
ticket=3
ticket=2
ticket=1
ticket=5
但是如果加入了sleep方法,
class MyThreadSync implements Runnable{
private int ticket=5;
public void run(){
  for(int i=0;i<100;i++){
   if(ticket>0){
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println("ticket="+ticket);
    ticket--;
   }
  }
}
}
public class SyncDemo {
public static void main(String args[]){
  MyThreadSync mt=new MyThreadSync();
  Thread t1=new Thread(mt);
  Thread t2=new Thread(mt);
  Thread t3=new Thread(mt);
  t1.start();
  t2.start();
  t3.start();
}
}
结果又变成:
ticket=5
ticket=4
ticket=4
ticket=2
ticket=1
ticket=1
ticket=-1

为什么会出现这种结果?
第1个问题:使用Runnable不是可以共享操作吗?为什么ticket=4又会出现2次?
第2个问题:sleep方法的作用是什么?
ticket=5
ticket=4
ticket=3
ticket=2
ticket=1
ticket=-1

作者: 叶久瑞    时间: 2012-7-30 22:36
第一个问题:你这是出现了线程的安全问题,对于线程的安全问题,我做了一下的总结,希望能够帮到你:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        多线程的安全问题。。
安全问题产生的原因
(1)        多个线程在操作共享数据
(2)        操作共享数据的代码有多条
一个线程在执行多条操作共享数据的过程中其他线程参与了运算
这时就会发生安全问题。

想要分析是否有安全问题
依据:线程任务中有没有共享数据,该数据是否被多条语句操作啊

解决方案:只要保证一个线程在执行多条操作共享数据的语句时,其他线程不能参与运算即可。
当该线程都执行后,其他线程才可以执行这些语句。。

代码表现:java中给我们提供了具体的解决语句,
                        那就是同步代码块。
格式:synchronized(对象)   //对象可以是任意的对象
{
                需要被同步的语句。
}

同步的原理,其实就是将需要同步的代码进行封装,并在该代码上加了一个锁
同步的好处:解决了多线程的安全问题。
同步的弊端:有了同步会降低性能,对性能有损耗。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二个问题:
sleep是让线程处于冻结状态,这样的话,其他线程就可以进来,所以会出现你的那个ticket=4打印两次,后面的时候还有一个wait,作用跟sleep很像。但是也是有区别的。我对此也有总结,在下面,你可以参考一下:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

wait()和sleep()方法的异同点:

两个方法都可以让线程处于冻结状态。
sleep()必须指定时间,wait是可以指定时间,也可以不指定。

synchronized(obj)
{
        sleep();
}

sleep():会释放执行权,不会释放锁。
wait():会释放执行权,会释放锁。

作者: 贾成龙    时间: 2012-7-30 22:44
第一个问题:Runnable是可以共享操作的,解决了thread类中static共享数据生命周期过长的问题。你的结果出现两个四是因为你没有加同步锁。
第二个问题:sleep的作用:就是释放执行权,不释放锁,使其处于冻结状态,因为肯定可以恢复到临时阻塞状态。还有就是必须指定时间!
作者: 金龙    时间: 2012-7-30 23:25
通过实现Runnable方法创建的线程资源是共享的,通过直接继承Thread方法创建的线程资源是不共享的,貌似不值一分,提个醒吧~
其他的楼上都答的挺好,也不给我留啥补充的,一脸淡定的飘过了……

作者: 王峰    时间: 2012-7-30 23:45
java 多线程 资源共享

在控制资源共享的语句外,加入 synchronized(this)  (this也可用private Object o 对象),来进行写锁保护 ,例如
class M
{
        private static M m = new M();
        public static M getInstance()
        {
                return m;
        }
       
        public void check(int i)
        {
                System.out.println("I"m waiting, Thread "+i);
                synchronized(this)
                {
                        System.out.println("I"m processing, Thread "+i);
                        try {
                                Thread.sleep(5000l);
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                }
        }
        synchronized void method(int i)
        {
                System.out.println("I"m in synchronized function "+ i);
                try {
                        Thread.sleep(1000l);
                } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        }
}
public class CheckCloneable implements Runnable
{
        private int i;
        private boolean test_function_syn;
        CheckCloneable(int i,boolean test_function_syn)
        {
                this.i = i;
                this.test_function_syn = test_function_syn;
        }
        public void run()
        {
                M m = M.getInstance();
                if(!test_function_syn)
                {
                        m.check(i);
                }
                else
                {
                        System.out.println("I"m waiting synchronized function "+ i);
                        m.method(i);
                }
        }
       
        public static void main(String[] args)
        {
                for(int i=0;i<5;i++)
                {
                        System.out.println("main");
                        CheckCloneable c = new CheckCloneable(i,true);
                        Thread t = new Thread(c);
                        t.start();
                }
        }
}




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2