java synchronsized简述
synchronsized关键字在解决多线程的并发问题具有举足轻重的位置
-
对象锁
形式1:同步代码块:synchronsized(object){}
形式2:synchronsized加到普通方法上即为对象锁:public synchronsized void method(){} -
类锁
形式1:把synchronsized加到静态方法上即为类锁:public static synchronsized void method(){}
形式2:同步代码块:synchronsized (Object.class){} -
对象锁和类锁的区别:
对象锁指的是对象,也就是当是类的同一个对象时synchronsized才会同步,如果是类的不同对象实例那么synchronsized并不会如我们预期的也同步,这里面最关键的便是要理解类的实例对象是不是相同的。
而如果要达到我们预期的不管任何类的实例对象也能同步,那么便要使用类锁。类锁是对所有类对象实例起作用,而对象锁只对当前实例对象起作用,同一类的不同实例对象之间的对象锁互不影响。
方法抛出异常后,锁会自动被释放
如果在synchronsized方法里调用了一个普通方法,由于synchronsized只对当前方法有效,因此那个普通方法仍然是非线程安全的
可重入性
- synchronsized的可重入性是的好处:避免死锁 ,synchronsized作用的是线程,只要是同一线程,不管是类的同一方法还是不同类的方法都是可重入的,只要是同一把锁,就可以继续使用,这样就能避免死锁,同时也提高代码的封装性,不用进行频繁的加锁释放锁。
原理
- 利用javah 反编译class文件时可以看到加锁和释放锁用的其实就是monitorenter和monitorexit指令
monitorenter会使锁的计数加1,monitorexit会使锁的计数减1,只有当计数变为0时,其他线程才有机会获得锁
缺陷
- 效率低:释放锁的情况少,试图获得锁时不能设定超时,不能中断一个正在试图获得锁的线程
- 不够灵活:加锁和释放的时机单一
- 无法知道是否成功获取到锁
这些缺陷可以用Lock解决。
注意点
- 锁对象不能为空,锁的信息是放在锁对象头里的
- 作用域不能过大,过大就失去了多线程的优势
- 避免死锁
其他
-
线程6个状态
NEW(新建)、RUNNABLE(运行)、BLOCKED(锁池)、TIMED_WAITING(定时等待)、WAITING(等待)、TERMINATED(终止、结束) -
join方法
Thread中,join()方法的作用是调用线程等待该线程完成后,才能继续用下运行,就是调用这个join方法的线程会阻塞在那里,直到join的线程执行完毕后才会继续下去。
join的简单用法就是当有两个线程在执行,而我们需要等待这两个线程执行完毕后再做一些操作时便可用join
public static void main(String[] args){
Thread t1=new Thread();
Thread t2=new Thread();
t1.join();
t2.join();
System.out.println("end");//end 会在t1,t2两个线程都执行完后再执行
}
-
sleep()方法是Thread类里面的,主要的意义就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后又会自动恢复运行状态。
-
wait()方法是Object类里面的,主要的意义就是让线程放弃当前的对象的锁,进入等待此对象的等待锁定池,只有针对此对象调动notify方法后本线程才能够进入对象锁定池准备获取对象锁进入运行状态。