线程并发学习----线程阻塞(synchronized)

线程并发学习

线程并发学习—-核心概念(转载)
线程并发学习—-线程阻塞(sleep、wait、notifyAll、notify、join)
线程并发学习—-线程阻塞(synchronized)
线程并发学习—-线程阻塞(lock)
线程并发学习—-Thread、Runnable、Callable
线程并发学习—-队列(Queue)
spring学习—-线程池
java中一些锁概念整理(转载)

简介

在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。

通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。

Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。在共享内存并发模型里,同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。

线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,

一是存在共享数据(也称临界资源),
二是存在多条线程共同操作共享数据。

在 Java 中synchronized 和 lock可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块

关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代Volatile功能),这点确实也是很重要的。

synchronized三种使用方式

  • 修饰实例方法
  • 修饰静态方法
  • 修饰同步代码块

修饰实例方法

实例代码

public class NormalFunctionSyncDemo {
   public static void main(String[] args) {
        NormalFunctionSyncDemo normalFunctionSyncDemo = new NormalFunctionSyncDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                normalFunctionSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                NormalFunctionSyncDemo normalFunctionSyncDemo2 = new NormalFunctionSyncDemo();
                normalFunctionSyncDemo2.getB();
            }
        }).start();
    }


    public synchronized void getA(){
        System.out.println("get A.....");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public synchronized void getB(){

        System.out.println("get B.....");
        System.out.println("end B");

    }
}

结果分析

使用同一个实例对象,会阻塞
get A…..
end A
get B…..
end B
使用不同实例对象,不会阻塞
get A…..
get B…..
end B
end A

修饰静态方法

代码示例

public class StaticFunctionSyncDemo {
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticFunctionSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticFunctionSyncDemo staticFunctionSyncDemo = new StaticFunctionSyncDemo();
                staticFunctionSyncDemo.getB();
                StaticFunctionSyncDemo.getA();
            }
        }).start();
    }


    public static synchronized void getA(){
        System.out.println("get A.....");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public synchronized void getB(){
        System.out.println("get B.....");
        System.out.println("end B");
    }
}

结果分析

通类直接调用或创建新的示例调用getA方法都会阻塞,getB方法不会

get A…..
get B…..
end B
end A
get A…..
end A

修饰同步代码块

代码示例

public class StaticBlockSyncDemo {
    public static void main(String[] args) {
        StaticBlockSyncDemo staticBlockSyncDemo = new StaticBlockSyncDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                staticBlockSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticBlockSyncDemo staticBlockSyncDemo2 = new StaticBlockSyncDemo();
                staticBlockSyncDemo.getB();
            }
        }).start();
    }


    public void getA(){
        System.out.println("get A.....");
        try {
            synchronized (this) {
                System.out.println("Method A execute");
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public  void getB(){
        System.out.println("get B.....");
        try {
            synchronized (this) {
                System.out.println("Method B execute");
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end B");
    }
}

结果分析

结果与实例方法类似,通过monitor监视器锁实现

monitor监视器锁

public void getA();
    Code:
       0: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #12                 // String get A.....
       5: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: aload_0
       9: dup
      10: astore_1
      //通过javap命令可以看到获取monitor锁
      11: monitorenter
      12: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #14                 // String Method A execute
      17: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: ldc2_w        #15                 // long 3000l
      23: invokestatic  #17                 // Method java/lang/Thread.sleep:(J)V
      26: aload_1
      27: monitorexit

参考资料
http://blog.csdn.net/javazejian/article/details/72828483?locationNum=5&fps=1
http://www.cnblogs.com/paddix/p/5374810.html

你可能感兴趣的:(线程并发)