1. 方法内的变量为线程安全, 实例变量非线程安全
方法中的变量不存在非线程安全问题, 永远是线程安全的. 这是方法内部的变量是私有的特性造成的.
如果多个线程共同访问 1 个对象中的实例变量, 则有可能出现 "非线程安全" 问题.
2. 多个对象多个锁
关键字 synchronized 取得的锁都是对象锁, 而不是把一段代码或方法 (函数) 当作锁, 哪个线程先执行带 synchronized 关键字的方法, 哪个线程就持有该方法所属对象的锁, 其他线程只能呈等待状态, 前提是多个线程访问的是同一个对象. 但如果多个线程访问多个对象, 则 JVM 会创建多个锁.
多个线程访问一个对象 --》创建一个对象锁
多个线程访问多个对象 --》创建多个对象锁
3.synchronized 方法与锁对象
1 ) A 线程先持有 object 对象的 Lock 锁, B 线程可以以异步的方式调用 object 对象中的非 synchronized 类型的方法.
2 ) A 线程先持有 object 对象的 Lock 锁, B 线程如果在这时调用 object 对象中的 synchronized 类型的方法则需等待, 也就是同步.
4.synchronized 锁重入
关键字 synchronized 拥有锁重入的功能, 也就是在使用 synchronized 时, 当一个线程得到一个对象锁后, 再次请求此对象锁时是可以再次得到该对象的锁的.
"可重入锁" 的概念是: 自己可以再次获取自己的内部锁. 比如有 1 条线程获得了某个对象的锁, 此时这个对象锁还没有释放, 当其再次想要获取这个对象的锁的时候还是可以获取的, 如果不可锁重入的话, 就会造成死锁.
- 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");
- }
- }
- View Code
- public class MyThread extends Thread {
- public static void main(String[] args) {
- (new MyThread()).start();
- }
- @Override
- public void run() {
- super.run();
- Service service = new Service();
- service.service1();
- }
- }
- View Code
5. 同步不具备继承性
同步不具备继承, 所以还得在子类的方法中添加 synchronized 关键字
6.synchronized 同步代码块
1)用关键字 synchronized 声明方法在某些情况下是有弊端的, 比如 A 线程调用同步方法执行一个长时间的任务, 那么 B 线程则必须等待比较长时间. 在这样的情况下可以使用 synchronized 同步语句块来解决.
2)当两个并发线程访问同一个对象中的 synchronized(this)同步代码块时, 一段时间内只能有一个线程被执行, 另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.
3)不在 synchronized 块中就是异步执行, 在 synchronized 块中就是同步执行.
4)和 synchronized 方法一样, synchronized(this)代码块也是锁定当前对象的.
7. 同步方法与同步代码块
多个线程调用同一个对象中的不同名称的 synchronized 同步方法或 synchronized(this)同步代码块时, 调用的效果就是按顺序执行, 也就是同步的, 阻塞的.
1.synchronized 同步方法
1 )对其他 synchronized 同步方法或 synchronized(this)同步代码块调用呈阻塞状态.
2 )同一时间只有一个线程可以执行 synchronized 同步方法中的代码.
2. synchronized(this)同步代码块
1 )对其他 synchronized 同步方法或 synchronized(this)同步代码块调用呈阻塞状态.
2 )同一时间只有一个线程可以执行 synchronized(this)同步代码块中的代码.
8. 将任意对象作为对象监视器
Java 还支持对 "任意对象" 作为 "对象监视器" 来实现同步的功能. 这个 "任意对象" 大多数是实例变量及方法的参数, 使用格式为 synchronized(非 this 对象).
1)在多个线程持有 "对象监视器" 为同一个对象的前提下, 同一时间只有一个线程可以执行 synchronized(非 this 对象 x)同步代码块中的代码.
2)当持有 "对象监视器" 为同一个对象的前提下, 同一时间只有一个线程可以执行 synchronized(非 this 对象 x)同步代码块中的代码.
优点: 如果在一个类中有很多个 synchronized 方法, 这时虽然能实现同步, 但会受到阻塞, 所以影响运行效率; 但如果使用同步代码块锁非 this 对象, 则
synchronized(非 this)代码块中的程序与同步方法是异步的, 不与其他锁 this 同步方法争抢 this 锁, 则可大大提高运行效率.
使用 "synchronized(非 this 对象 x) 同步代码块" 格式进行同步操作时, 对象监视器必须是同一个对象. 如果不是同一个对象监视器, 运行的结果就是异步调用了, 就会交叉运行.
- public class UserService {
- private String username;
- private String password;
- private String str = new String();
- public void set(String username, String password) {
- synchronized (str) {
- try {
- System.out.println(Thread.currentThread().getName() + ":begin:" + System.currentTimeMillis());
- this.username = username;
- Thread.sleep(3000);
- System.out.println(Thread.currentThread().getName() + ":end:" + System.currentTimeMillis());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- View Code
- public class ThreadA extends Thread{
- private UserService userService;
- public ThreadA(UserService userService) {
- this.userService = userService;
- }
- @Override
- public void run() {
- userService.set("a","aa");
- }
- }
- public class ThreadB extends Thread{
- private UserService userService;
- public ThreadB(UserService userService) {
- this.userService = userService;
- }
- @Override
- public void run() {
- userService.set("b","bb");
- }
- }
- View Code
- public class Run {
- public static void main(String[] args) {
- UserService userService = new UserService();
- ThreadA a = new ThreadA(userService);
- a.setName("A");
- a.start();
- ThreadB b = new ThreadB(userService);
- b.setName("B");
- b.start();
- }
- }
- View Code
更改 UserService.java 的代码, 在 set 方法中创建 str 对象. 同步代码块异步执行了, 因为两个线程获得的对象锁不是同一个.
- public class UserService {
- private String username;
- private String password;
- public void set(String username, String password) {
- String str = new String();
- synchronized (str) {
- try {
- System.out.println(Thread.currentThread().getName() + ":begin:" + System.currentTimeMillis());
- this.username = username;
- Thread.sleep(3000);
- System.out.println(Thread.currentThread().getName() + ":end:" + System.currentTimeMillis());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- View Code
来源: http://www.bubuko.com/infodetail-3338106.html