Java多线程编程中synchronized线程同步的教程

0.关于线程同步
(1)为什么需要同步多线程?
线程的同步是指让多个运行的线程在一起良好地协作,达到让多线程按要求合理地占用释放资源。我们采用Java中的同步代码块和同步方法达到这样的目的。比如这样的解决多线程无固定序执行的问题:

public class TwoThreadTest {
  public static void main(String[] args) {
    Thread th1= new MyThread1();
    Thread th2= new MyThread2();
    th1.start();
    th2.start();
  }
}

class MyThread2 extends Thread{
  @Override
  public void run() {
    for( int i=0;i<10;i++)
      System. out.println( "thread 1 counter:"+i);
  }
}

class MyThread1 extends Thread{
  @Override
  public void run() {
    for( int i=0;i<10;i++)
      System. out.println( "thread 2 counter:"+i);
  }
}

这种状态下多线程执行的结果是随机地去任意插入执行,这完全取决于JVM对于线程的调度,在很多要求定序执行的情况下,这种随机执行的状态显然是不合要求的。

public class ThreadTest {
  public static void main(String[] args) {
    MyThread thread = new MyThread();
    Thread th1= new Thread(thread);
    Thread th2= new Thread(thread);
    th1.start();
    th2.start();
  }

}

class MyThread implements Runnable{
  @Override
  public synchronized void run() {
    for( int i=0;i<10;i++)
      System. out.println(Thread. currentThread().getName()+" counter:"+i);
  }
}

使用了同步方法后我们就可以控制线程独占执行体对象,这样在执行的过程中就可以使得线程将执行体上的任务一次性执行完后退出锁定状态,JVM再调度另一个线程进来一次性运行执行体内的任务。

(2)线程创建运行的范式:
在以前我们也有自己的线程创建和运行的编程范式,一般是定义一个执行类重写run()方法,但是这种方式将执行体和执行的任务放在了一起,从软件工程的角度来看不利于解耦。一个线程的执行的意思是说线程通过执行对象执行了某个对象的某个任务,从这个角度来说,将任务的规定者从执行类中分离出来可以使得多线程编程的各个角色明晰出来,进而获得良好地解耦,以下就是线程创建和执行的编程范式:

public class FormalThreadClass {
  public static void main(String[] args) {
    Thread thread = new Thread( new MyRunnable());
    thread.start();
  }
}

class MyRunnable implements Runnable{
  MyTask myTask = new MyTask();
  @Override
  public void run() {
    myTask.doTask();
  }
}

class MyTask{
  public void doTask() {
    System. out.println( "This is real Tasking");
  }
}

1. synchronized原理
在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。
当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。
不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。

2. synchronized基本规则
我们将synchronized的基本规则总结为下面3条,并通过实例对它们进行说明。
第一条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
第二条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
第三条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
(1)第一条:
当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。 下面是“synchronized代码块”对应的演示程序。

class MyRunable implements Runnable {

 @Override
 public void run() {
  synchronized(this) {
   try {
    for (int i = 0; i < 5; i++) {
     Thread.sleep(100); // 休眠100ms
     System.out.println(Thread.currentThread().getName() + " loop " + i);
    }
   } catch (InterruptedException ie) {
   }
  }
 }
}

public class Demo1_1 {

 public static void main(String[] args) {
  Runnable demo = new MyRunable();  // 新建“Runnable对象”

  Thread t1 = new Thread(demo, "t1"); // 新建“线程t1”, t1是基于demo这个Runnable对象
  Thread t2 = new Thread(demo, "t2"); // 新建“线程t2”, t2是基于demo这个Runnable对象
  t1.start();       // 启动“线程t1”
  t2.start();       // 启动“线程t2”
 }
}

运行结果:

t1 loop 0
t1 loop 1
t1 loop 2
t1 loop 3
t1 loop 4
t2 loop 0
t2 loop 1
t2 loop 2
t2 loop 3
t2 loop 4

结果说明:run()方法中存在“synchronized(this)代码块”,而且t1和t2都是基于"demo这个Runnable对象"创建的线程。这就意味着,我们可以将synchronized(this)中的this看作是“demo这个Runnable对象”;因此,线程t1和t2共享“demo对象的同步锁”。所以,当一个线程运行的时候,另外一个线程必须等待“运行线程”释放“demo的同步锁”之后才能运行。
如果你确认,你搞清楚这个问题了。那我们将上面的代码进行修改,然后再运行看看结果怎么样,看看你是否会迷糊。修改后的源码如下:

class MyThread extends Thread {

 public MyThread(String name) {
  super(name);
 }

 @Override
 public void run() {
  synchronized(this) {
   try {
    for (int i = 0; i < 5; i++) {
     Thread.sleep(100); // 休眠100ms
     System.out.println(Thread.currentThread().getName() + " loop " + i);
    }
   } catch (InterruptedException ie) {
   }
  }
 }
}

public class Demo1_2 {

 public static void main(String[] args) {
  Thread t1 = new MyThread("t1"); // 新建“线程t1”
  Thread t2 = new MyThread("t2"); // 新建“线程t2”
  t1.start();       // 启动“线程t1”
  t2.start();       // 启动“线程t2”
 }
}

代码说明:比较Demo1_2 和 Demo1_1,我们发现,Demo1_2中的MyThread类是直接继承于Thread,而且t1和t2都是MyThread子线程。
幸运的是,在“Demo1_2的run()方法”也调用了synchronized(this),正如“Demo1_1的run()方法”也调用了synchronized(this)一样!
那么,Demo1_2的执行流程是不是和Demo1_1一样呢?运行结果:

t1 loop 0
t2 loop 0
t1 loop 1
t2 loop 1
t1 loop 2
t2 loop 2
t1 loop 3
t2 loop 3
t1 loop 4
t2 loop 4

结果说明:
如果这个结果一点也不令你感到惊讶,那么我相信你对synchronized和this的认识已经比较深刻了。否则的话,请继续阅读这里的分析。
synchronized(this)中的this是指“当前的类对象”,即synchronized(this)所在的类对应的当前对象。它的作用是获取“当前对象的同步锁”。
对于Demo1_2中,synchronized(this)中的this代表的是MyThread对象,而t1和t2是两个不同的MyThread对象,因此t1和t2在执行synchronized(this)时,获取的是不同对象的同步锁。对于Demo1_1对而言,synchronized(this)中的this代表的是MyRunable对象;t1和t2共同一个MyRunable对象,因此,一个线程获取了对象的同步锁,会造成另外一个线程等待。
(2)第二条:
当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
下面是“synchronized代码块”对应的演示程序。

class Count {

 // 含有synchronized同步块的方法
 public void synMethod() {
  synchronized(this) {
   try {
    for (int i = 0; i < 5; i++) {
     Thread.sleep(100); // 休眠100ms
     System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
    }
   } catch (InterruptedException ie) {
   }
  }
 }

 // 非同步的方法
 public void nonSynMethod() {
  try {
   for (int i = 0; i < 5; i++) {
    Thread.sleep(100);
    System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
   }
  } catch (InterruptedException ie) {
  }
 }
}

public class Demo2 {

 public static void main(String[] args) {
  final Count count = new Count();
  // 新建t1, t1会调用“count对象”的synMethod()方法
  Thread t1 = new Thread(
    new Runnable() {
     @Override
     public void run() {
      count.synMethod();
     }
    }, "t1");

  // 新建t2, t2会调用“count对象”的nonSynMethod()方法
  Thread t2 = new Thread(
    new Runnable() {
     @Override
     public void run() {
      count.nonSynMethod();
     }
    }, "t2"); 

  t1.start(); // 启动t1
  t2.start(); // 启动t2
 }
}

运行结果:

t1 synMethod loop 0
t2 nonSynMethod loop 0
t1 synMethod loop 1
t2 nonSynMethod loop 1
t1 synMethod loop 2
t2 nonSynMethod loop 2
t1 synMethod loop 3
t2 nonSynMethod loop 3
t1 synMethod loop 4
t2 nonSynMethod loop 4

结果说明:
主线程中新建了两个子线程t1和t2。t1会调用count对象的synMethod()方法,该方法内含有同步块;而t2则会调用count对象的nonSynMethod()方法,该方法不是同步方法。t1运行时,虽然调用synchronized(this)获取“count的同步锁”;但是并没有造成t2的阻塞,因为t2没有用到“count”同步锁。
(3)第三条:
当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
我们将上面的例子中的nonSynMethod()方法体的也用synchronized(this)修饰。修改后的源码如下:

class Count {

 // 含有synchronized同步块的方法
 public void synMethod() {
  synchronized(this) {
   try {
    for (int i = 0; i < 5; i++) {
     Thread.sleep(100); // 休眠100ms
     System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
    }
   } catch (InterruptedException ie) {
   }
  }
 }

 // 也包含synchronized同步块的方法
 public void nonSynMethod() {
  synchronized(this) {
   try {
    for (int i = 0; i < 5; i++) {
     Thread.sleep(100);
     System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
    }
   } catch (InterruptedException ie) {
   }
  }
 }
}

public class Demo3 {

 public static void main(String[] args) {
  final Count count = new Count();
  // 新建t1, t1会调用“count对象”的synMethod()方法
  Thread t1 = new Thread(
    new Runnable() {
     @Override
     public void run() {
      count.synMethod();
     }
    }, "t1");

  // 新建t2, t2会调用“count对象”的nonSynMethod()方法
  Thread t2 = new Thread(
    new Runnable() {
     @Override
     public void run() {
      count.nonSynMethod();
     }
    }, "t2"); 

  t1.start(); // 启动t1
  t2.start(); // 启动t2
 }
}

运行结果:

t1 synMethod loop 0
t1 synMethod loop 1
t1 synMethod loop 2
t1 synMethod loop 3
t1 synMethod loop 4
t2 nonSynMethod loop 0
t2 nonSynMethod loop 1
t2 nonSynMethod loop 2
t2 nonSynMethod loop 3
t2 nonSynMethod loop 4

结果说明:
主线程中新建了两个子线程t1和t2。t1和t2运行时都调用synchronized(this),这个this是Count对象(count),而t1和t2共用count。因此,在t1运行时,t2会被阻塞,等待t1运行释放“count对象的同步锁”,t2才能运行。

3. synchronized方法 和 synchronized代码块
“synchronized方法”是用synchronized修饰方法,而 “synchronized代码块”则是用synchronized修饰代码块。
synchronized方法示例

public synchronized void foo1() {
  System.out.println("synchronized methoed");
}
synchronized代码块
public void foo2() {
  synchronized (this) {
    System.out.println("synchronized methoed");
  }
}

synchronized代码块中的this是指当前对象。也可以将this替换成其他对象,例如将this替换成obj,则foo2()在执行synchronized(obj)时就获取的是obj的同步锁。
synchronized代码块可以更精确的控制冲突限制访问区域,有时候表现更高效率。下面通过一个示例来演示:

// Demo4.java的源码
public class Demo4 {

  public synchronized void synMethod() {
    for(int i=0; i<1000000; i++)
      ;
  }

  public void synBlock() {
    synchronized( this ) {
      for(int i=0; i<1000000; i++)
        ;
    }
  }

  public static void main(String[] args) {
    Demo4 demo = new Demo4();

    long start, diff;
    start = System.currentTimeMillis();        // 获取当前时间(millis)
    demo.synMethod();                // 调用“synchronized方法”
    diff = System.currentTimeMillis() - start;    // 获取“时间差值”
    System.out.println("synMethod() : "+ diff);

    start = System.currentTimeMillis();        // 获取当前时间(millis)
    demo.synBlock();                // 调用“synchronized方法块”
    diff = System.currentTimeMillis() - start;    // 获取“时间差值”
    System.out.println("synBlock() : "+ diff);
  }
}

(某一次)执行结果:

synMethod() : 11
synBlock() : 3

4. 实例锁 和 全局锁
实例锁 -- 锁在某一个实例对象上。如果该类是单例,那么该锁也具有全局锁的概念。
(1)实例锁对应的就是synchronized关键字。
(2)全局锁 -- 该锁针对的是类,无论实例多少个对象,那么线程都共享该锁。
全局锁对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。
关于“实例锁”和“全局锁”有一个很形象的例子:

pulbic class Something {
  public synchronized void isSyncA(){}
  public synchronized void isSyncB(){}
  public static synchronized void cSyncA(){}
  public static synchronized void cSyncB(){}
}

假设,Something有两个实例x和y。分析下面4组表达式获取的锁的情况。
(1) x.isSyncA()与x.isSyncB()
(2) x.isSyncA()与y.isSyncA()
(3) x.cSyncA()与y.cSyncB()
(4) x.isSyncA()与Something.cSyncA()

(1) 不能被同时访问。
因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!

// LockTest1.java的源码
class Something {
  public synchronized void isSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public synchronized void isSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
}

public class LockTest1 {

  Something x = new Something();
  Something y = new Something();

  // 比较(01) x.isSyncA()与x.isSyncB()
  private void test1() {
    // 新建t11, t11会调用 x.isSyncA()
    Thread t11 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            x.isSyncA();
          }
        }, "t11");

    // 新建t12, t12会调用 x.isSyncB()
    Thread t12 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            x.isSyncB();
          }
        }, "t12"); 

    t11.start(); // 启动t11
    t12.start(); // 启动t12
  }

  public static void main(String[] args) {
    LockTest1 demo = new LockTest1();
    demo.test1();
  }
}

运行结果:

t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB

(2) 可以同时被访问

因为访问的不是同一个对象的同步锁,x.isSyncA()访问的是x的同步锁,而y.isSyncA()访问的是y的同步锁。

// LockTest2.java的源码
class Something {
  public synchronized void isSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public synchronized void isSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
}

public class LockTest2 {

  Something x = new Something();
  Something y = new Something();

  // 比较(02) x.isSyncA()与y.isSyncA()
  private void test2() {
    // 新建t21, t21会调用 x.isSyncA()
    Thread t21 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            x.isSyncA();
          }
        }, "t21");

    // 新建t22, t22会调用 x.isSyncB()
    Thread t22 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            y.isSyncA();
          }
        }, "t22"); 

    t21.start(); // 启动t21
    t22.start(); // 启动t22
  }

  public static void main(String[] args) {
    LockTest2 demo = new LockTest2();

    demo.test2();
  }
}

运行结果:

t21 : isSyncA
t22 : isSyncA
t21 : isSyncA
t22 : isSyncA
t21 : isSyncA
t22 : isSyncA
t21 : isSyncA
t22 : isSyncA
t21 : isSyncA
t22 : isSyncA

(3) 不能被同时访问
因为cSyncA()和cSyncB()都是static类型,x.cSyncA()相当于Something.isSyncA(),y.cSyncB()相当于Something.isSyncB(),因此它们共用一个同步锁,不能被同时反问。

// LockTest3.java的源码
class Something {
  public synchronized void isSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public synchronized void isSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
}

public class LockTest3 {

  Something x = new Something();
  Something y = new Something();

  // 比较(03) x.cSyncA()与y.cSyncB()
  private void test3() {
    // 新建t31, t31会调用 x.isSyncA()
    Thread t31 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            x.cSyncA();
          }
        }, "t31");

    // 新建t32, t32会调用 x.isSyncB()
    Thread t32 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            y.cSyncB();
          }
        }, "t32"); 

    t31.start(); // 启动t31
    t32.start(); // 启动t32
  }

  public static void main(String[] args) {
    LockTest3 demo = new LockTest3();

    demo.test3();
  }
}

运行结果:

t31 : cSyncA
t31 : cSyncA
t31 : cSyncA
t31 : cSyncA
t31 : cSyncA
t32 : cSyncB
t32 : cSyncB
t32 : cSyncB
t32 : cSyncB
t32 : cSyncB

(4) 可以被同时访问
因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。

// LockTest4.java的源码
class Something {
  public synchronized void isSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public synchronized void isSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : isSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncA(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncA");
      }
    }catch (InterruptedException ie) {
    }
  }
  public static synchronized void cSyncB(){
    try {
      for (int i = 0; i < 5; i++) {
        Thread.sleep(100); // 休眠100ms
        System.out.println(Thread.currentThread().getName()+" : cSyncB");
      }
    }catch (InterruptedException ie) {
    }
  }
}

public class LockTest4 {

  Something x = new Something();
  Something y = new Something();

  // 比较(04) x.isSyncA()与Something.cSyncA()
  private void test4() {
    // 新建t41, t41会调用 x.isSyncA()
    Thread t41 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            x.isSyncA();
          }
        }, "t41");

    // 新建t42, t42会调用 x.isSyncB()
    Thread t42 = new Thread(
        new Runnable() {
          @Override
          public void run() {
            Something.cSyncA();
          }
        }, "t42"); 

    t41.start(); // 启动t41
    t42.start(); // 启动t42
  }

  public static void main(String[] args) {
    LockTest4 demo = new LockTest4();

    demo.test4();
  }
}

运行结果:

t41 : isSyncA
t42 : cSyncA
t41 : isSyncA
t42 : cSyncA
t41 : isSyncA
t42 : cSyncA
t41 : isSyncA
t42 : cSyncA
t41 : isSyncA
t42 : cSyncA
时间: 2016-07-02

解析Java编程之Synchronized锁住的对象

图片上传 密码修改为  synchronized是java中用于同步的关键字,一般我们通过Synchronized锁住一个对象,来进行线程同步.我们需要了解在程序执行过程中,synchronized锁住的到底是哪个对象,否则我们在多线程的程序就有可能出现问题. 看下面的代码,我们定义了一个静态变量n,在run方法中,我们使n增加10,然后在main方法中,我们开辟了100个线程,来执行n增加的操作,如果线程没有并发执行,那么n最后的值应该为1000,显然下面的程序执行完结果不是1000,因为我们

Java中synchronized关键字修饰方法同步的用法详解

Java的最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问. 每一个用synchronized关键字声明的方法都是临界区.在Java中,同一个对象的临界区,在同一时间只有一个允许被访问. 静态方法则有不同的行为.用synchronized关键字声明的静态方法,同时只能够被一个执行线程访问,但是其他线程可以访问这个对象的非静态的synchronized方法.必须非常谨慎这一点,因为两个线程可以同时访问一个对象的两个不同的synchronized方法,即其中一个是静态s

Java多线程编程中synchronized关键字的基础用法讲解

多线程编程中,最关键.最关心的问题应该就是同步问题,这是一个难点,也是核心. 从jdk最早的版本的synchronized.volatile,到jdk 1.5中提供的java.util.concurrent.locks包中的Lock接口(实现有ReadLock,WriteLock,ReentrantLock),多线程的实现也是一步步走向成熟化.   同步,它是通过什么机制来控制的呢?第一反应就是锁,这个在学习操作系统与数据库的时候,应该都已经接触到了.在Java的多线程程序中,当多个程序竞争同一

实例解析Java中的synchronized关键字与线程安全问题

首先来回顾一下synchronized的基本使用: synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步.这叫减小锁的粒度,使代码更大程度的并发. synchronized方法,被修饰的方法成为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象. synchronized静态方法,修饰一个static静态方法,其作用范围是整个

java synchronized同步静态方法和同步非静态方法的异同

java synchronized 详解 synchronized关键字有两种用法,一种是只用于方法的定义中,另外一种是synchronized块,我们不仅可以使用synchronized来同步一个对象变量,你也可以通synchronizedl来同步类中的静态方法和非静态方法. synchronized块的语法如下: public void method() { synchronized(表达式) { } } public void method() { synchronized(表达式) {

简单了解Java synchronized关键字同步

synchronized synchronized可以用来同步块,同步方法.同步块可以用来更精确地控制对象锁,控制锁的作用域.(锁的作用域就是从锁的获得到锁的释放的时间,而且可以选择获取哪个对象的锁).但是在使用同步块机制时,过多的使用锁也会引发死锁问题,同时获取和释放也有代价. 而同步方法,它所拥有的就是该类的对象,换句话说,就是this对象,而且锁的作用域是整个方法,这可能导致锁的作用域太大,有可能导致死锁问题.同时也可能包括了不需要同步的代码块在内,也会降低程序的运行效率. 不管是同步方法

基于synchronized修饰静态和非静态方法

前言 最近被问到了这个问题,第一次回答的也是很不好,在此参考网上答案进行整理记录.供大家学习参考. Synchronized修饰非静态方法 Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称"对象锁". Java中每个对象都有一个锁,并且是唯一的.假设分配的一个对象空间,里面有多个方法,相当于空间里面有多个小房间,如果我们把所有的小房间都加锁,因为这个对象只有一把钥匙,因此同一时间只能有一个人打开一个小房间,然后用完了还回去,再由JVM 去分配下一个获得钥匙的

JAVA中堆、栈,静态方法和非静态方法的速度问题

一.堆和栈的速度性能分析 堆和栈是JVM内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内容,存储空间大小,存储速度这几个方面来理解的,但是关于堆和栈的存储速度,只知道堆存储速度慢,栈存储速度快,至于为什么堆比栈的存取速度慢,并没有特别深入的研究,从网上也找了很多资料,但很多理由并不太认同,这里也列举一些,并结合自己的理解来分析,如果不正确欢迎指正. 1.从分配的角度分析 java中栈的大小和生命周期在编译期间就确定了的(可以参考之前写的一篇JVM内存模型中的分析,

PHP静态调用非静态方法的应用分析

静态调用非静态方法!!这在java,c#中是不可想象的,也是绝对不行的.这样的错误在这些语言中会在编译阶段就被指出错误的.但是对于php这样的动态语言呢?首先这个是语法没有错误的,php –l 找不出错误来的.如果运行呢?先看一个例子 复制代码 代码如下: <?php class myClass {     private $name = "myClass"; public function echoName(){         echo $this->name;    

Java中CountDownLatch进行多线程同步详解及实例代码

Java中CountDownLatch进行多线程同步详解 CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantLock.ReadWriteLock锁实现同步. 3.信号量Semaphore实现同步. 其中,synchronized关键字和Lock锁解决的是多个线程对同一资源的并发访问问题.信号量Semaphore解决的是多副本资源的共享访问问题. 今天

java 线程之对象的同步和异步(实例讲解)

一.多线程环境下的同步与异步 同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去. package com.jalja.org.thread.demo01; public class Thread02 { public synchronized void method1(){ System.out.println("method1:"+Thread.currentThread().getName()); try { T

浅析php静态方法与非静态方法的用法区别

在php编程中,static关键字声明一个属性或方法是和类相关的,而不是和类的某个特定的实例相关,因此,这类属性或方法也称为"类属性"或"类方法" 如果访问控制权限允许,可不必创建该类对象而直接使用类名加两个冒号"::"调用. static关键字可以用来修饰变量.方法. 不经过实例化,就可以直接访问类中static的属性和static的方法. static 的属性和方法,只能访问static的属性和方法,不能类访问非静态的属性和方法.因为静态属性

Java并发之传统线程同步通信技术代码详解

本文研究的主要是Java并发之传统线程同步通信技术的相关代码示例,具体介绍如下. 先看一个问题: 有两个线程,子线程先执行10次,然后主线程执行5次,然后再切换到子线程执行10,再主线程执行5次--如此往返执行50次. 看完这个问题,很明显要用到线程间的通信了, 先分析一下思路:首先肯定要有两个线程,然后每个线程中肯定有个50次的循环,因为每个线程都要往返执行任务50次,主线程的任务是执行5次,子线程的任务是执行10次.线程间通信技术主要用到wait()方法和notify()方法.wait()方