Java多线程编程学习chapter2

java多线程编程核心技术chapter2


多线程的同步,也就是在Java语言中写出线程安全的程序,,如何解决非线程相关的问题
1.synchronized对象监测器为Object时的使用
2.synchronized对象监测器为Class时的使用
3.非线程安全是如何出现的
4.关键字volatile的主要作用
5.关键字volatile与synchronized的区别和使用情况

线程不安全
在多个线程对同一个对象中的实例变量进行并发访问时发生,出现脏读,也就是取到的数据是被更改过的
线程安全
获得的实例变量是经过同步处理的,不会出现脏读

非线程安全的问题存在于实例变量中
方法内的变量为线程安全的,这是方法内部的变量是私有的特性造成的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\functionfieldsafe\FunctionFieldSafe.java

两个线程访问一个没有同步的方法,同时操作业务对象中的实例变量,则有可能出现非线程安全的
解决办法就是加上synchronized关键字
参照代码:SimpleThread\src\com\nineclient\call\chapter2\objectfieldsafe\ObjectFieldUnSafe.java
解决办法就是加上synchronized关键字  synchronized public void addI(String username )

结论:两个线程访问同一个对象中的同步方法时一定是线程安全的

多个对象多个锁
当两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果是异步执行的
关键字synchronized取得的锁是对象锁,并不是把一个代码片段当作锁
哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属的锁Lock,那么其他线程就只能等待,前提是多个线程访问的是同一个对象。
如果是多个线程多个对象,则JVM会创建多个锁。互不干扰。
synchronized, asynchronized
参照代码:SimpleThread\src\com\nineclient\call\chapter2\objectfieldsafe\MultiObjectLock.java

synchronized和锁对象
调用关键字synchronized声明的方法一定是排队运行的,只有共享资源的读写访问才需要同步化,如果不是共享资源,根本没有同步的必要
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synmethodlockobject\SynMethodLockObject.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synmethodlockobject\SynMethodLockObject1.java

结论:A线程先持有objec对象的Lock锁,B线程可以以异步的方式调用objec对象中的非synchronized类型的方法
A线程先持有object对象的Lock锁,B线程如果这时调用object对象中的synchronized类型的方法则需等待,也就是同步
参照代码:\SimpleThread\src\com\nineclient\call\chapter2\synmethodlockobject\TwoMethodLockOne.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synmethodlockobject\TwoMethodLockTwo.java

脏读
发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过
参照代码:SimpleThread\src\com\nineclient\call\chapter2\publicvar\PublicVar.java
加上synchronized,就可以解决脏读

synchronized锁重入
可锁重入,自己可以再次获取自己的内部锁,比如一条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象锁的时候还是可以获取的,如果不可锁重入会造成死锁
参照代码:SimpleThread\src\com\nineclient\call\chapter2\publicvar\Service1_3.java

可锁重入也支持在父子类继承环境中,子类完全可以通过可锁重入调用父类的同步方法
参照代码:SimpleThread\src\com\nineclient\call\chapter2\publicvar\SubFather.java

当一个线程执行的代码出现异常时,其所持有的锁自动释放
参照代码:SimpleThread\src\com\nineclient\call\chapter2\releaselock\ReleaseLockWhenException.java

同步不具有继承性
参照代码:SimpleThread\src\com\nineclient\call\chapter2\releaselock\SynchronizedNOExtend.java

synchronized同步语句块
synchronized方法是对当前对象进行加锁,synchronized代码块是对某一个对象进行加锁
synchronized弊端,假如处理一个长时间的任务,其他线程等待时间长
参照代码:SimpleThread\src\com\nineclient\call\chapter2\baddot\BadDot.java

synchronized同步代码块的使用
当两个并发线程访问同一个对象Object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
参照代码:SimpleThread\src\com\nineclient\call\chapter2\baddot\SynchronizedBlock.java
执行效果还是同步的

用同步代码块来解决运行时间长的弊端
当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)代码块
参照代码:SimpleThread\src\com\nineclient\call\chapter2\quick\Quickly.java
结论:synchronized同步代码块的确是同步的,真的持有当前对象的锁

一半异步,一般同步
不在synchronized块中的就是异步,在synchronized块中的就是同步执行
参照代码:

synchronized代码块之间的同步性
当一个线程访问一个对象的synchronized(this)代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块将被阻塞,这说明synhcronized使用的是同一个对象监视器
参照代码:

验证同步synchronized(this)代码块锁定的是当前对象和synchronzied方法一样
参照代码:

将任意对象作为对象监视器,同一时间只有一个synchronized(非this)同步代码块可以执行
这个任意对象大多数是实例变量及方法的参数,使用格式为synchronized(非this对象)
参照代码:SimpleThread\src\com\nineclient\call\chapter2\anyobject\AnyObject.java

synchronized(非this对象)和synchronized方法是一步的,不和其他锁this同步方法争抢this锁
如果不是同一个对象监视器,运行结果是异步的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\diffobject\DifferentObject.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\diffobject\DiffObject1.java

线程调用方法的顺序是无序的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\diffobject\ThreadNoSort.java
由于两个线程方法的顺序不确定,所以当两个线程执行带有分支判断的方法时,就会出现逻辑上的错误,可能出现脏读
参照代码:SimpleThread\src\com\nineclient\call\chapter2\anyobject\MyOneObject.java

验证是三个结论
当多个线程同时执行synchronized(x) 同步代码块时呈同步效果
当其他线程执行x对象中的synchronized同步方法时呈同步效果
当其他线程执行x对象中的synchronized(this)代码块时也呈同步效果
参照代码:SimpleThread\src\com\nineclient\call\chapter2\checkthree\CheckThreeResult.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\checkthree\CheckThreeResult1.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\checkthree\CheckThreeResult2.java

静态同步synchronized方法和synchronized(class)代码块
关键字synchronized还可以应用在static静态方法上,那是对当前.java文件对应的class文件进行加锁
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synchronizedclass\SynchronizedClass.java

验证synchronzied加在非static方法上是对象锁,synchronzied加到static方法上是给class类上锁    
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synchronizedclass\DiffObjectLock.java

一个对象锁,一个class锁,Class锁对所有的对象实例都起作用
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synchronizedclass\MoreObjectOneSynObject.java

synchronized(class) 代码块的作用和synchronized static 方法作用是一样的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\synchronizedclass\SynObjectSynBlock.java

数据类型的String的常量池特性
JVM中具有String常量池缓存功能。
当传入的String字符串参数相同时,两个线程就具有相同的锁
解决办法是同步代码块都不使用String作为锁对象
参照代码:SimpleThread\src\com\nineclient\call\chapter2\stringobject\StringObject.java

同步synchronzied方法无线等待与解决,用同步代码块解决
参照代码:SimpleThread\src\com\nineclient\call\chapter2\stringobject\DeadLock.java

多线程死锁
因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成,死锁是必须避免的,以为是说会造成线程假死
参照代码:SimpleThread\src\com\nineclient\call\chapter2\stringobject\DeathThread.java
到JDK安装目录的bin目录下,执行jps,得到线程run的id值是假如是000,再执行jstack命令,jstack -l 000

内置类和静态内置类
参照代码:SimpleThread\src\com\nineclient\call\chapter2\Innerclass\InnerClass.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\Innerclass\InnerClass1.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\Innerclass\PublicClass.java
参照代码:SimpleThread\src\com\nineclient\call\chapter2\Innerclass\PublicClass1.java

内置类中有两个同步方法,不同的锁,是异步执行的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\Innerclass\InnerMain.java

锁对象的改变
只要是锁的对象获得的时候是不一样的,执行就是异步的
参照代码:SimpleThread\src\com\nineclient\call\chapter2\changeobject\ChangeLockObject.java

只要对象不变,即使对象的属性被改变,运行结果还是同步的
参照代码:

volatile关键字
作用是使变量在多个线程之间可见
关键字volatile与死循环
同步死循环的例子
参照代码:SimpleThread\src\com\nineclient\call\chapter2\changeobject\DealSynDeadLock.java
上面的例子放在server上,还是会出现死循环,解决办法是用volatile关键字
private boolean isCon = true ;
存在于公共堆栈和线程私有堆栈中,在JVM设置成-server模式时,为了线程的执行效率,线程一直是在私有堆栈中取得iscon的值,而代码 a .setCon( false );虽然被执行,但是更新的是公共堆栈的变量,所以一直是死循环
volatile和synchronized的比较
volatile是线程同步的轻量级实现,性能比synchronized好,volatile只能修饰变量,synchronized可以修饰方法和代码块
多线程访问volatile变量时,不会阻塞,而synchronized会阻塞
volatile保证数据的可见性,但是不能保证原子性,synchronzed保证了原子性,也间接保证了可见性
volatile解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间同步性

解决同步死循环,多线程解决
解决异步死循环,用关键字volatile关键字,强制从公共堆栈中进行取值,感知实例变量被更改了,多线程读取共享变量时可以获得最新的值。
volatile保证可见性,不保证原子性
i++是线程不安全的,从内存中读取i值,计算i的值,将i值写到内存中
参照代码:SimpleThread\src\com\nineclient\call\chapter2\changeobject\VolatileNoSafe.java

read  load
use assign
store write
原子类型,在没有锁的情况下,做到线程安全
原子类也不一定安全:方法是原子的,但是方法与方法之间的调用却不是原子的,解决这样的问题是要同步
原子类有:AtomicInteger AtomicLong

最后一个列子好欣慰
还是工作内存和主内存的数据不一致
参照代码:SimpleThread\src\com\nineclient\call\chapter2\changeobject\GoodService.java
             while ( iscon ) {
                   synchronized ( "aaa" ) {
                  }
            }

保证可视性和同步性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值