JAVA线程之五:线程的同步

来源:互联网 发布:虚拟机连不上网络 编辑:程序博客网 时间:2024/04/27 20:13

      如果程序是单线程,执行起来不必担心此线程会被其他线程打扰,就像在现实中,同一时间只完成一件事情,可以不用担心这件事情会被其他事情打扰。但是如果程序中同时使用多线程,就好比现实中“两个人同时进入一扇门”,此时就需要控制,否则容易阻塞。为了避免多线程共享资源发生冲突的情况,只要在线程使用资源时给该资源上一把锁就可以了,访问资源的第一个线程为资源上锁,其他线程若想使用这个资源必须等到锁解除为止,锁解除的同时另一个线程使用该资源并为这个资源上锁。
      为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制指的是两个线程同时作用在一个对象时,应该保持对象数据的统一性和整体性。Java提供synchronized关键字,为防止资源冲突提供了内置支持。共享资源一般是文件、输入/输出端口,或是打印机。Java中同步有两种形式,分别介绍如下。
一,同步方法
      同步方法将访问这个资源的方法都标记为synchronized,这样在需要调用这个方法的线程执行完成之前,其他调用标志为synchronized()方法的线程都会被阻塞。可以使用如下代码声明一个synchronized()方法。
synchronized void sum(){...}            //定义一个取和的同步方法
synchronized void max(){...}            //定义一个取最大值的同步方法
上述代码中定义了两个同步方法,其中第一个方法为取和操作,第二个方法取最大值操作,当两个方法同时作用于内存中同一块地址时,如果此对象调用了sum()方法,此时max()方法只能等到sum()方法调用完毕并且释放锁之后才能被调用。
      看如下实例:src/com/wsy/TestSynchronizedThread.java完整代码:
package com.wsy;
public class TestSynchronizedThread extends Thread

{
      private char cha;
      public TestSynchronizedThread(char cha)

     {
            this.cha=cha;
      }
      synchronized void printch()

      {
            for(int i=0;i<5;i++)
                 System.out.print(cha);
      }
      public void run()

     {
            printch();
            System.out.println();
      }
      public static void main(String[] args)

     {
            TestSynchronizedThread t1=new TestSynchronizedThread('A');
            TestSynchronizedThread t2=new TestSynchronizedThread('B');
            t1.start();
            t2.start();
      }
}

运行结果是:
  AAAAA
  BBBBB

实验证明如果printch前不加synchronized ,输出结果还可能是ABBBBB AAAA等。此时两个线程是一起交错执行的并没有同步。
二,同步块
       Java中同步的设定不只应用于同步化方法,也可以设置某个程序的区域块为同步化区域,例如:
synchronized(someobject){
……//省略代码
}
其中somobject代表当前对象,同步的作用区域是synchronized关键字后大括号以内的部分。在程序执行到synchronized设定的被同步化区块时锁定当前对象,这样就没有其他线程可以执行这个被同步化的区域块了。
      例如有线程A与线程B,A与B都希望同时访问同步块内的代码,此时,线程A进入同步区域块执行,而线程B不能进入同步区域块而不得不等待。简单地说,只有拥有可以运行代码权限的线程才可以运行同步块内的代码。当线程A从同步块中退出时,线程A需要释放someobject对象,使等待的线程B获得这个对象,然后执行同步块内的代码。
      下面看一个同步块的例子,用于3个线程同时打印字符串,操作步骤如下。
src/com/wsy/TestSynchronizedThread2.java完整代码:
package com.wsy;
public class TestSynchronizedThread2 extends Thread

{
      private String cha;
      static Object printer=new Object();
      public TestSynchronizedThread2(String cha)

     {
            this.cha=cha;
      }
      void print()

      {
            synchronized(printer)

            {
                  for(int i=1;i<=3;i++)
                         System.out.print(cha+" ");
             }
      }
      public void run()

      {
             for(int i=1;i<3;i++)

             {
                    print();
                    System.out.println();   //换行
             }
       }
       public static void main(String[] args)

       {
              TestSynchronizedThread2 test1=new TestSynchronizedThread2("线程A");
              TestSynchronizedThread2 test2=new TestSynchronizedThread2("线程B");
              TestSynchronizedThread2 test3=new TestSynchronizedThread2("线程C");
              test1.start();
              test2.start();
              test3.start();
      }
}     

理论执行结果:     
线程A  线程A  线程A  
线程A  线程A  线程A  
线程B  线程B  线程B     
线程B  线程B  线程B 
线程C  线程C  线程C     
线程C  线程C  线程C      

实验证明有几点注意:

(1) 上面的synchronized部分只是固定了单行输出,一行跟另一行之间的顺序并不固定。

线程A 线程A 线程A
线程A 线程A 线程A
线程B 线程B 线程B 线程C 线程C 线程C
线程C 线程C 线程C

线程B 线程B 线程B

(2)如果synchronized是针对run函数体内,也只是固定同一个线程内的两行输出,不同两行之间的输出顺序并不固定。

(3)如果没有设定优先级,线程的启动顺序跟执行顺序并不一致。比如:在(2)的基础上,仍然可能输出:

线程A 线程A 线程A
线程A 线程A 线程A
线程C 线程C 线程C
线程C 线程C 线程C
线程B 线程B 线程B
线程B 线程B 线程B

 

 

                                 

 

参考原文:http://www.isstudy.com/java/1963_3.html       

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 四岁宝宝吐了怎么办啊 3岁宝宝突然吐了怎么办 宝宝撑着了吐拉怎么办 2岁宝宝体温37.5怎么办 宝宝2岁乳牙烂了怎么办 孕40周还没入盆怎么办 孕妇脸上长斑了怎么办 七个月宝宝大便干怎么办 两月大婴儿不拉大便怎么办 周岁宝宝大便出血了怎么办 十一个月宝宝大便干燥怎么办 8个月宝宝大便干燥怎么办 7个月宝宝大便干燥怎么办 11个月宝宝大便干燥怎么办 9个月宝宝大便干燥怎么办 10个月宝宝大便干燥怎么办 宝宝两天没拉粑粑了怎么办 小学闺蜜嫉妒我怎么办 三年级孩子对应用题理解很差怎么办 我嫉妒我的朋友怎么办 嫉妒同学比我好怎么办 宝宝生在家里了怎么办 在家不小心生了怎么办 葫芦干了有黑点怎么办 单位费用发票丢失了怎么办 1岁宝宝太调皮了怎么办 孩子和同学打架家长该怎么办 孩子被大人打了怎么办 小孩不跟大人沟通怎么办 2岁小朋友爱动手怎么办 小班爱动手的小朋友怎么办 宝宝对小朋友不友好爱动手怎么办 小孩子上幼儿园爱打人怎么办 小孩被别人打了怎么办 1岁幼儿爱打人怎么办 作为幼小朋友打人老师怎么办 2岁半小朋友喜欢打人怎么办 2岁宝宝脾气大怎么办 4月小孩爱动怎么办 一岁宝宝老打人怎么办 1岁宝宝爱打人怎么办