Synchronized是Java的关键字,同步锁
修饰对象由如下几种
1 修饰代码块,被修饰的代码块称为 同步语句块,锁作用的对象时调用该代码块的对象
2修饰方法,被修饰的方法称为同步方法,锁作用的对象 是 调用这个方法的对象
3修饰静态方法,锁作用的对象 是 这个类的所有对象。
4修饰类,锁作用的对象 是 这个类的所有对象。
代码转载于LovelyBear2019的博客
1 修饰代码块
一个线程访问一个对象的synchronized(this)修饰的代码块时,同一时间,其他试图访问该对象的线程将被阻塞
如下,当两个并发线程thread1 和thread2 访问同一个对象syncThread中的synchronized代码块时,在同一个时刻只能有一个线程得到执行,另一个线程收到阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。
class SyncThread implements Runnable {
private static int count;
public SyncThread() {
count = 0;
}
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + "-" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public int getCount() {
return count;
}
}
public class Synchronized_1 {
public static void main(String[] args) {
SyncThread syncThread = new SyncThread();
Thread thread1 = new Thread(syncThread, "SyncThread1");
Thread thread2 = new Thread(syncThread, "SyncThread2");
thread1.start();
thread2.start();
}
}
结果为:
SyncThread1-0
SyncThread1-1
SyncThread1-2
SyncThread1-3
SyncThread1-4
SyncThread2-5
SyncThread2-6
SyncThread2-7
SyncThread2-8
SyncThread2-9
把调用当时改变一下:
Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
thread1.start();
thread2.start();
结果为:
SyncThread1-0
SyncThread2-1
SyncThread2-2
SyncThread1-3
SyncThread2-4
SyncThread1-5
SyncThread2-6
SyncThread1-7
SyncThread2-8
SyncThread1-9
原因为:
这时候创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run)
会有两个锁,分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行
可以给某个指定对象加锁:
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 class Synchronized_4 {
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();
}
}
结果为:
Thread0:10000.0
Thread4:10000.0
Thread3:10000.0
Thread2:10000.0
Thread1:10000.0
用synchronized给account对象加了锁,当一个线程访问account对象时,其他试图访问account对象的线程将会阻塞,知道该线程访问account对象结束。谁再拿到那个锁的控制,就可以运行加锁代码
2 给方法加锁
两种写法等价,都是锁定了整个方法时的内容
public synchronized void method() {
// todo
}
public void method() {
synchronized(this) {
// todo
}
}
注意:
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(); }
}
3 修饰一个静态方法
静态方法是属于类的而不属于对象的。同样的,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 class Synchronized_5 {
public static void main(String[] args) {
SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();
}
}
结果为:
SyncThread1-0
SyncThread1-1
SyncThread1-2
SyncThread1-3
SyncThread1-4
SyncThread2-5
SyncThread2-6
SyncThread2-7
SyncThread2-8
SyncThread2-9
4修饰一个类
class SyncThread implements Runnable {
private static int count;
public SyncThread() {
count = 0;
}
public static void method() {
synchronized(SyncThread.class) {
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();
}
}