2、对象及变量的并发访问 -- Java多线程编程核心技术

1、synchronized同步方法

	synchronized解决的问题:当多个线程对同一个对象中的实例变量进行并发
访问时,可能会产生“脏读”,也就是取的的数据其实是被更改过的数据,即“非线程
安全”现象。而synchronized可以让多线程对方法或语句块进行同步调用,从而避
免这种现象。发生“脏读”的情况是在读取实例变量时,此值已经被其他线程更改过
了。脏读一定会出现在操作实例变量的情况下,脏读是通过synchronized关键字进
行解决的。

	非线程安全问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在
“非线程安全”问题。因为synchronized同步方法锁的是对象,而不是方法本身,
当多个线程访问的是同一个对象的时候,那么多个线程也使用了同一个实例变量。
但是一个类中的相同的方法内部的私有变量,在多线程进行访问的时候,每个线程
访问到的变量却是不同的。所以也就不存在“非线程安全”问题。

	当多个线程共同访问一个对象中的实例变量时,可能会产生“非线程安全”问题,
解决办法:使用synchronized将方法变为同步方法。

	synchronized方法锁定的是锁对象,而不是方法本身,只要线程访问的对象
不同,那么调用的方法就不是同步的,例如:
	1、A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object
	对象中的非synchronized类型的方法;
	2、A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中
	的synchronized类型的方法,就需要等待,也就是同步。

	当一个线程执行的代码出现异常时,其所持有的锁会自动释放。

	同步是不具有继承性的。当子类重写了父类的同步方法,但是子类的方法名前
并没有加上synchronized关键字时,子类的该方法并不是同步方法。

	关键字synchronized具有锁重入的功能,即当一个线程得到一个对象锁之后,
再次请求此对象锁时,是可以再次得到该对象的锁的。也就证明了在一个
synchronized方法/同步语句块的内部调用本类的其他synchronized方法/同步
语句块时,是永远可以得到的。

线程类MyThread

package extthread;
import service.Service;
public class MyThread extends Thread {
    @Override
    public void run() {
        Service service = new Service();
        service.service1();
    }
}
package service;
public class Service {
    synchronized public void service1() {
        System.out.println("service1");
        service2();
    }
    synchronized public void service2() {
        System.out.println("service2");
        service3();
    }
    synchronized public void service3() {
        System.out.println("service3");
    }
}

运行类Run

package test;
import extthread.MyThread;
public class Run {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start();
    }
}

运行结果如下:
在这里插入图片描述

	可重入锁的概念是:自己可以再次获取自己的内部锁,比如有一条线程获得了
某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时
候,还是可以获取的,如果不可锁重入的话,就会造成死锁。

	可重入锁也支持在父子类继承中。当存在父子类继承关系时,子类是完全可以
通过“可重入锁”调用父类的同步方法的。

2、synchronized同步语句块

	synchronized方法是对当前对象进行加锁,而synchronized代码块是对某
一个对象进行加锁。
public class ObjectService {
	public void serviceMethod() {
		try {
			synchronized (this) {
				System.out.println("begin time=" + System.currentTimeMillis());
				Thread.sleep(2000);
				System.out.println("end    end=" + System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
	同步方法和同步代码块的区别就是,同步方法同步的是方法内的代码,同步方
法块同步的是方法块内的代码。可以通过自己设定同步代码块的位置来提升程序的
运行时间。

	不管是同步方法还是同步代码块,锁定的都是对象,而不是代码。都是对象锁。
	
	synchronized(this)同步代码块中的this可以替换为其他的对象,当this
替换为其他的对象之后,同步代码块锁定的就是其他的对象了,而不是当前对象。
如果this为String类型,那么值相同的两个String对象,代表的是同一个对象。
	
	静态同步synchronized方法和synchronized(class)代码块:
	关键字synchronized还可以应用在static静态方法上,这样写之后,是对当
前的java文件对应的class类进行加锁。
	synchronized关键字加到static静态方法上是给class类上锁,而
synchronized关键字加到非static静态方法上是给对象加锁。
	类锁有两种表现形式:	
	synchronized(class)代码块、synchronized static方法。
	类锁锁住的是类,当同一个类的不同对象访问的相同或不同的类锁方法时,是
同步的。但是当一个对象访问类锁方法,另一个对象访问对象锁方法时,是异步的。
类锁和对象锁互不影响。

	当多个线程互相等待对方释放锁时,就有可能产生死锁。

	当一个锁对象有多个属性时,即使对象的属性发生了改变,但是那个锁对象不会发生改变。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值