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

来源:互联网 发布:总结 优化机构设置 编辑:程序博客网 时间:2024/06/05 11:51

线程并发学习

线程并发学习—-核心概念(转载)
线程并发学习—-线程阻塞(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