A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© clp 中级黑马   /  2013-5-23 16:34  /  1930 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 clp 于 2013-5-24 08:23 编辑

由于是自学,本人同步这一块学的稀里糊涂的,请求高手支招!!!

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 鼓励分,别误会

查看全部评分

5 个回复

正序浏览
yanzhigang 发表于 2013-5-23 20:19
这里的同步只对单个Java应用程序来说,至于数据库同步,文件同步等就不是这里讨论的问题了。


回答的仔细,拷下来好好琢磨,谢谢!
回复 使用道具 举报
楼主你好,如果问题以解决,请修改分类,谢谢合作。

尽量把问题全面一点提出来,如果不知道怎么提请看我的个性签名,点击红色的字体
回复 使用道具 举报


这里的同步只对单个Java应用程序来说,至于数据库同步,文件同步等就不是这里讨论的问题了。



同步和多线程的关系
1.没有多线程环境就不需要同步。
2.即使有多线程环境也不一定需要同步。



为什么要同步:
为了防止多个线程对同一数据的修改,所以需要同步,否则会造成数据不一致。
Java提供了非常方便的多线程支持,所以说同步问题比较普遍,尤其是Servlet和
JSP的线程安全问题特别明显。
http://blog.csdn.net/treeroot/archive/2004/09/03/93881.aspx



同步的实质:
Java同步其实就是获得对象的同步锁,其他线程就只能等待。我们的大部分程序都

不是线程安全的,因为没有进行同步,而且我们没有必要,因为大部分情况根本没

有多线程环境。

只举一个例子说明同步的实质。

代码1:
class SynTest{
    synchronized static method(){
//这个方法是同步的方法,每次只有一个线程可以进来
        System.out.println("begin");
        try{Thread.sleep(2000);}
        System.out.println("end");  
    }
    public static void main(String[] args){
       //启动10个线程,这里用了匿名类,因为确实方便不少。
       for(int i=0;i<10;i++){
            new Thread(){
                public void run(){
                    method();
                }
            }.start();
        }
    }
}
很容易看到每个线程必须等待前一个线程退出方法method后才可以进去。
上面的同步方法可以有另外的两种等价方式:



代码2:
class SynTest{
    static method(){
        synchronized(SynTest.class){
          //这个方法虽然不是同步的方法,但是每次只有一个线程可以进到同步块
          System.out.println("begin");
          try{Thread.sleep(2000);}
          System.out.println("end");
        }  
    }
    public static void main(String[] args){
       //启动10个线程,这里用了匿名类,因为确实方便不少。
       for(int i=0;i<10;i++){
            new Thread(){
                public void run(){
                    method();
                }
            }.start();
       }
    }
}



代码3:
class SynTest{
    private static Object lock=new Object();
    static method(){
           synchronized(lock){
          //这个方法用一个专门的对象作为锁。
          System.out.println("begin");
          try{Thread.sleep(2000);}
          System.out.println("end");
        }  
    }
    public static void main(String[] args){
       //启动10个线程,这里用了匿名类,因为确实方便不少。
       for(int i=0;i<10;i++){
            new Thread(){
                public void run(){
                    method();
                }
            }.start();
       }
    }
}



其实上面三种情况基本上是等价的,不过第三种方式很常见,估计会有性能上的提

高吧,毕竟锁定一个小对象看起来比锁定一个大对象容易一点。



上面的是静态方法,如果是非静态的话,代码2的表现为 synchronized(this)。
这里先说明一点,同步和是否线程安全和方法是否是静态的一点关系都没有。



如果判断一个类或者一个方法是否线程安全的呢?
假设一个类没有提供直接修改成员变量的操作,也就是算只能通过方法修改
对象。我们很容易得出结论,只有所有的方法是线程安全的,这个类才是线程
安全的。那么如何判断一个方法是否线程安全的,只有看说明文档或者阅读源码了

,不过可以肯定的说大部分都不是线程安全的,从方法声明是看不出来的。
class Math{
     public static int safePow(int x,int y){//假设y大于0
        int res=x;
        for(int i=1;i<y;i++) res*=x;
        return res;
     }
     public static int unsafePow(int x,int y){
        pow=y;
        return pow(x);
     }
     private static int pow;
     private static int pow(int x){
        int res=x;
        for(int i=1;i<pow;i++) res*=x;
        return res;
     }
}
我都不知道怎么回举这么无聊的例子,而且我发现这个问题脑子里很清楚,却很难

表达清楚,看一下两个线程调用unsafePow的例子。
Thread1: unsafePow(3,3);
Thread2:     unsafePow(2,2);
假设Thread1执行到 pow=y;进入方法pow(int x);
此时pow=3;
然后Thread2执行pow=y; 进入方法pow(int x);
此时pow=2;
然后线程1执行pow(int x)方法应该等到的是3的2次方,导致错误,所以说
这个方法不是线程安全的。



线程安全的关键就是对成员变量的修改(类变量或者实例变量,两者在这里都是
一样的),而且对于访问方法同样存在线程安全问题。
我们知道Hashtable是线程安全的,因为所有的方法都同步了,也就是说最多只能同

时有一个线程对Hashtable操作,那么我们认为它是线程安全的。那么假设它的size()方法不同步,
那就有可能你调用size方法还没有返回,一个线程又添加了一个数据,这个时候你读取到的值应该是正确

的值,但是这个size方法还没有返回,又一个线程删除了一个数据,这个时候你返回的就是一个错误的大小了。



Hashtable也需要同步,当然Hashtable是线程安全的,Java文档也有说明,但是不

等于线程安全就不要同步压。
public class SynHashtable{
public static void main(String[] args)
{
  final Hashtable ht=new Hashtable();
  ht.put(new Object(),"Quick to Death");
  
  new Thread(){
   public void run(){
    while(true){
     if(ht.size()<10){
      ht.put(new



Object(),"object");
     }
     else{
      ht.clear();
     }
    }
   }
  }.start();
  
  new Thread(){
   public void run(){
    unsafe(ht);
   }
  }.start();
   
  
}



static void unsafe(Hashtable ht){
  while(true){
  //synchronized(ht){
  Iterator it=ht.values().iterator();
  while(it.hasNext())
   System.out.println(it.next());
  }
  //}
}
}
如果不同步的话很快就会崩溃。

建议多看看多线程安全问题   举例:买票问题。
public class Ticket implements Runnable
                {
                        //定义100张票
                        private int tickets = 100;
               
                        @Override
                        public void run()
                        {
                                while(true)
                                {
                                        synchronized(this){
                                                if(tickets>0)
                                                {
                                                        try{
                                                                Thread.sleep(10);
                                                        }catch(InterruptedException e){
                                                                e.printStackTrace();
                                                        }
                                                        System.out.println(Thread.currentThread().getName()+"正在卖出第"+(tickets--)+"张票");
                                                }
                                        }
                                }
                        }
                }

                public class Test
                {
                        public static void main(String[] args)
                        {
                                Ticket t = new Ticket();

                                Thread t1 = new Thread(t,"窗口1");
                                Thread t2 = new Thread(t,"窗口2");
                                Thread t3 = new Thread(t,"窗口3");
                                Thread t4 = new Thread(t,"窗口4");
                               
                                t1.start();
                                t2.start();
                                t3.start();
                                t4.start();
                        }
                }

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 太长了

查看全部评分

回复 使用道具 举报
暂时只学到基础第六天,加油!
看操作系统原理时知道同步锁是很重要的,比如网上买电影票,两个人不能同时选定一个座位进行付款。
回复 使用道具 举报
今天刚学完同步,感觉同步就是为了实现线程安全,把多个线程中的代码加上同一个锁对象, 同一时间就只能执行一段了。同步这段有Synchronized 关键字是一种实现同步的方法,包括同步代码块和同步函数两种,还有就是用ReentrantLock类了,用它里边的newCondition 方法。还有就是进程之间的通信,有wait()、notify()、notifyAll()这几个方法。还有在JDK5之后出现的await()方法和signal()方法,这两个方法实现的话更能体现面向对象的思想

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马