synchronized的区别,synchronized 作用
如何解决写爬虫IP受阻的问题?立即使用。
1. synchronized锁重入
1.1 介绍
关键字synchronized具有锁重入的功能,即在使用synchronized时,当一个线程获得一个对象锁并再次请求该对象锁时,可以再次获得该对象的锁。这表明,当在一个同步方法/块中调用该类的其他同步方法/块时,总是可以获得锁。
例如:
公共类服务1 {
公共同步void方法1(){
system . out . println( method 1 );
method 2();
}
公共同步void方法2(){
system . out . println( method 2 );
method 3();
}
公共同步void方法3(){
system . out . println( method 3 );
}
}公共类MyThread扩展线程{
@覆盖
公共无效运行(){
service 1 service 1=new service 1();
service 1 . method 1();
}
公共静态void main(String[] args) {
MyThread MyThread=new MyThread();
myth read . start();
}
}运行结果如下:
看到这个结果我不知所措。怎么证明是可重入锁?
“可重入锁”的概念是您可以再次获得自己的内部锁。比如一个线程获取了一个对象的锁,这个对象的锁还没有被释放,当它想再次获取这个对象的锁的时候仍然可以获取。如果锁无法重新进入,将会导致死锁。
“重入锁”最大的作用是避免死锁。
1.2 分析
我们知道,在程序中,不可能在同步监视器上显式释放锁,但是在下列情况下锁会被释放:
执行结束时释放当前线程的同步方法和代码块。
当同步方法或同步代码块遇到break或return终止代码块或方法时,释放当前线程。
当未处理的错误或异常导致异常结束时释放。
程序执行同步对象的wait方法,当前线程暂停并释放锁。
然后,在上面的程序中,线程在进入同步方法method1时获得Service1的对象锁,但在执行method1时调用同步方法method2。按照正常情况,它在执行同步方法method2时也需要获得对象锁。但根据上述释放锁的条件,method1的对象锁此时还没有被释放,会导致死锁,无法继续执行method2。但是根据上面代码的执行结果,method2和method3可以正常执行,也就是说,在一个Synchronized修饰的方法或代码块的内部调用本类的其他Synchronized修饰的方法或代码块时,是永远可以得到锁的。
1.3 父子可继承性
在父子类继承的环境中支持重入锁。示例代码如下:
公共类服务2 {
public int i=10
公共同步void mainMethod(){
I-;
system . out . println( main print I= I);
尝试{
thread . sleep(100);
} catch (InterruptedException e) {
e . printstacktrace();
}
}
}公共类服务3扩展了服务2 {
公共同步void子方法(){
尝试{
while (i0){
I-;
system . out . println( sub print I= I);
thread . sleep(100);
this . main method();
}
}catch (InterruptedException e){
e . printstacktrace();
}
}
}公共类MyThread扩展线程{
@覆盖
公共无效运行(){
service 3 service 3=new service 3();
service 3 . submethod();
}
公共静态void main(String[] args) {
MyThread MyThread=new MyThread();
myth read . start();
}
}运行结果如下:
这个过程说明,当存在父子类继承关系时,子类完全可以通过“重入锁”调用父类的同步方法。
2. 出现异常,锁自动释放
当线程执行的代码出现异常时,其持有的锁会自动释放。
验证码如下:
公共类服务4 {
公共同步void testMethod(){
if(Thread.currentThread()。getName()。等于( a ){
系统。出去。println( thread name= thread。当前线程().getName()运行开始时间= system。当前时间毫秒());
int I=1;
while (i==1){
if(( Math.random()).子字符串(0,8)。等于( 0.123456 ){
系统。出去。println( thread name= thread。当前线程().getName()“运行异常时间=”系统。当前时间毫秒());
//整数。解析int( a );
}
}
}否则{
系统。出去。println(线程B运行时间=系统。当前时间毫秒());
}
}
}公共类线程扩展线程{
私服4服务4;
公共线程一个(服务四服务4){
这个。服务4=服务4;
}
@覆盖
公共无效运行(){
服务4。测试方法();
}
}公共类ThreadB扩展线程{
私服4服务4;
公共线程乙(服务四服务4){
这个。服务4=服务4;
}
@覆盖
公共无效运行(){
服务4。测试方法();
}
}公共类主要{
公共静态void main(String[] args) {
尝试{
service 4 service 4=new service 4();
ThreadA a=new ThreadA(服务4);
答。setname(" a ");
答。start();
线程。睡眠(500);
ThreadB b=new ThreadB(服务4);
乙。集合名称( b );
乙。start();
} catch (InterruptedException e) {
e。printstacktrace();
}
}
}注意服务四类中Integer.parseInt(“a”);此时处于被注释状态,运行结果如下:
由于a线程没有错误,而(真),此时a线程处于无限循环状态,锁一直被a占用,b线程无法获得锁,即无法执行b线程。
将服务四类中Integer.parseInt(“a”);解开注释,执行的结果如下:
当a线程发生错误时,b线程获得锁从而执行,由此可见,当方法出现异常时,锁自动释放。
3. 将任意对象作为监视器
爪哇岛支持对"任意对象"作为"对象监视器"来实现同步的功能。这个"任意对象"大多数是实例变量及方法的参数,使用格式为同步(非这对象x)同步代码块。
示例代码如下:
公共类StringLock {
私有字符串锁=锁
公共空的方法(){
同步(锁定){
尝试{
System.out.println(当前线程: Thread.currentThread().getName()开始);
线程。睡眠(1000);
System.out.println(当前线程: Thread.currentThread().getName()结束);
} catch (InterruptedException e) {
e。printstacktrace();
}
}
}
公共静态void main(String[] args) {
最终字符串锁string lock=new string lock();
新线程(新Runnable() {
@覆盖
公共无效运行(){
弦锁。方法();
}
}, t1 ).start();
新线程(新Runnable() {
@覆盖
公共无效运行(){
弦锁。方法();
}
}, t2 ).start();
}
}运行结果如下:
锁非这对象具有一定的优点:如果在一个类中有很多个同步的方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率;但如果使用同步代码块锁非这对象,则同步(非这个)代码块中的程序与同步方法是异步的,不予其他锁这同步方法争抢这锁,则可大大提高运行效率。
4. 同步不具有继承性
父类的同步方法,在子类中重写后不加同步关键字,是不会同步的,所以还得在子类的方法中添加同步的关键字。
推荐学习:Java视频教程以上就是一起看看同步的的四个特性的详细内容,更多请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。