如果程序是单线程,执行起来不必担心此线程会被其他线程打扰,就像在现实中,同一时间只完成一件事情,可以不用担心这件事情会被其他事情打扰。但是如果程序中同时使用多线程,就好比现实中“两个人同时进入一扇门”,此时就需要控制,否则容易阻塞。为了避免多线程共享资源发生冲突的情况,只要在线程使用资源时给该资源上一把锁就可以了,访问资源的第一个线程为资源上锁,其他线程若想使用这个资源必须等到锁解除为止,锁解除的同时另一个线程使用该资源并为这个资源上锁。
      为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制指的是两个线程同时作用在一个对象时,应该保持对象数据的统一性和整体性。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