synchronized的补充
来源:互联网 发布:淘宝界面 购物车代码 编辑:程序博客网 时间:2024/06/08 03:14
因为之前对synchronized不是很了解,所以前面就照搬尚学堂的课程,这里经过一些学习,稍微有点理解了这个synchronized关键字的用法。下面就说一些synchronized注意事项:
- 当对某个对象进行锁定的时候
/** * 银行账户类 */class Account { String name; float amount; public Account(String name, float amount) { this.name = name; this.amount = amount; } //存钱 public void deposit(float amt) { amount += amt; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } //取钱 public void withdraw(float amt) { amount -= amt; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } public float getBalance() { return amount; }}/** * 账户操作类 */class AccountOperator implements Runnable{ private Account account; public AccountOperator(Account account) { this.account = account; } public void run() { synchronized (account) { account.deposit(500); account.withdraw(500); System.out.println(Thread.currentThread().getName() + ":" + account.getBalance()); } } public static void main(String[] args){ Account account = new Account("zhang san", 10000.0f); AccountOperator accountOperator = new AccountOperator(account); final int THREAD_NUM = 5; Thread threads[] = new Thread[THREAD_NUM]; for (int i = 0; i < THREAD_NUM; i ++) { threads[i] = new Thread(accountOperator, "Thread" + i); threads[i].start();} }}
输出结果:Thread3:10000.0 Thread2:10000.0 Thread1:10000.0 Thread4:10000.0 Thread0:10000.0
在AccountOperator 类中的run方法里,我们用synchronized 给account对象加了锁。这时,当一个线程访问account对象时,其他试图访问account对象的线程将会阻塞,直到该线程访问account对象结束。也就是说谁拿到那个锁谁就可以运行它所控制的那段代码。
- 当锁定的是静态类或者静态方法
看内存图,对于静态static类和方法是存放在方法去中的,和new出来的类调用方式是不一样的,所以对于static变量和方法其实无论怎么创建,调用的都是同一个地址,静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象。
/** - 同步线程 */class SyncThread implements Runnable { private static int count; public SyncThread() { count = 0; } public synchronized static void method() { for (int i = 0; i < 5; i ++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void run() { method(); } public static void main(String[] args){ Account account = new Account("zhang san", 10000.0f); AccountOperator accountOperator = new AccountOperator(account); final int THREAD_NUM = 5; Thread threads[] = new Thread[THREAD_NUM]; for (int i = 0; i < THREAD_NUM; i ++) { threads[i] = new Thread(accountOperator, "Thread" + i); threads[i].start();} }}
输出结果: SyncThread1:0 SyncThread1:1 SyncThread1:2 SyncThread1:3 SyncThread1:4 SyncThread2:5 SyncThread2:6 SyncThread2:7 SyncThread2:8 SyncThread2:9
- 多个线程访问synchronized和非synchronized代码块
一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。
public class TT implements Runnable{ private int b = 100; public synchronized void m1(){ b = 1000; try { Thread.sleep(1000); System.out.println("b="+b); } catch (InterruptedException e) { e.printStackTrace(); } } public void m2(){ System.out.println(b); } @Override public void run() { m1(); } public static void main(String[] args){ TT tt = new TT(); Thread t = new Thread(tt); t.start(); //在这个线程启动之后,会睡眠3秒钟 try { Thread.sleep(500); // 这个睡眠时间是让main线程休眠一会,要保证TT线程已经启动,已经执行到方法里面了 tt.m2(); //上面线程是启动锁定的线程,然而这个时候main线程还是可以启动。线程已经锁定了,b=1000了,main线程仍然在运行,而且输出 //为1000,所以线程虽然可以锁定,但是m2()方法没有锁定,仍然可以访问,所以main线程里面输出的不是100而是1000。 //说明一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。 } catch (InterruptedException e) { e.printStackTrace(); } }}
输出结果: 1000 b=1000
下面是另外一个实例:
public class CpoyTT implements Runnable{ private int b = 100; public synchronized void m1(){ b = 1000; try { Thread.sleep(2000); System.out.println("b="+b); } catch (InterruptedException e) { e.printStackTrace(); } } public void m2(){ try { Thread.sleep(1000); b = 2000; } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { m1(); } public static void main(String[] args){ CpoyTT tt = new CpoyTT(); Thread t = new Thread(tt); t.start(); //在这个线程启动之后,会睡眠3秒钟 tt.m2(); //同TT,main线程还是可以访问没有被锁定的方法,如果m2()中的睡眠时间少于m1()中的话,会改变b的值 }}
输出结果:b=2000
- 在用synchronized修饰方法时要注意以下几点:
synchronized关键字不能继承: 虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字
class Parent { public synchronized void method() { }}class Child extends Parent { public synchronized void method() { }}
在子类方法中调用父类的同步方法
class Parent { public synchronized void method() { }}class Child extends Parent { public void method() { super.method(); }}
- 在定义接口方法时不能使用synchronized关键字。
- 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。
参考博客
- synchronized的补充
- 关于synchronized关键字的一点补充
- 补充的
- lock与synchronized使用中的注意事项(持续补充)
- synchronized(class)、synchronized(this)与synchronized(object)的区别分析
- synchronized(this)、synchronized(class)与synchronized(Object)的区别
- synchronized与static synchronized 的区别以及synchronized继承问题
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- synchronized方法和synchronized块的区别
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- synchronized和static synchronized的比较
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- synchronized与static synchronized 的区别
- Java中try、catch、finally、return的执行顺序
- 动态规划(2)——01背包
- 乘法表
- 【MySQL】20个经典面试题
- [Leetcode]516. Longest Palindromic Subsequence
- synchronized的补充
- MySQL设计之三范式的理解
- 点亮人生中第一个发光二极管
- C++中简单的文本文件输入/输出
- Angular 控制器之间的通信
- chapter18 EventLoop和EventLoopGroup
- 一道切线和圆有关的几何证明题及解析解答
- 可控硅电路的电容电阻的作用
- 桥接模式(构造型设计模式)