对象锁
包括方法锁(默认锁对象为this,当前实例对象)和同步代码块锁(自己指定锁对象),分为两种情况.
- 在方法上修饰,此时该方法变为一个同步方法
-
同步方法
当一个方法使用synchronized修饰后,这个方法称为”同步方法”,即:多个线程不能同时在方法内部执行,只能有先后顺序的一个一个进行,将并发操作同一临界资源的过程改为同步执行就可以有效的解决并发安全问题。即到了synchronized修饰的部分,就必须完整执行完下一个才可以进去,强制排序。 ```java
class Table{ private int beans = 20;//桌子上有20个豆子 public synchronized int getBean(){//将这个方法称用synchronized,变成同步方法。 if(beans==0){ throw new RuntimeException(“没有豆子了!”); } Thread.yield();//让线程主动放弃CPU时间,模拟执行到这里没有时间发生线程切换 return beans—; } }
<a name="JiUVU"></a>
### 同步块
:::info
有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高并发效率,同步块可以更准确的控制需要多个线程排队执行的代码片段。
:::
<a name="QpEoW"></a>
#### 语法:
**同步监视器对象**即上锁的对象,要想保证同步块中的代码被多个线程同步运行,则要求多个线程看到的同步监视器对象是同一个。
```java
synchronized(同步监视器对象){
需要多线程同步执行的代码片段
}
public void buy(){
try {
Thread t =Thread.currentThread();//获取运行buy方法的线程
System.out.println(t.getName()+":正在挑衣服...");
Thread.sleep(5000);
//如下,
synchronized (this) {
// synchronized (new Object()){无效!多个线程看到的不是同一个锁对象
System.out.println(t.getName() + ":正在试衣服...");
Thread.sleep(5000);
}
System.out.println(t.getName()+":结账离开");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
类锁
指synchronize修饰静态的方法或指定锁对象为Class对象
在静态方法上使用synchronized
当在静态方法上使用synchronized后,该方法是一个同步方法.由于静态方法所属类,所以一定具有同步效果。
静态方法使用的同步监视器对象为当前类的类对象(Class的实例)。
注:类对象会在后期反射知识点介绍。
public static void main(String[] args){
Thread t1 = new Thread(){
public void run(){
Foo.dosome();
}
};
Thread t2 = new Thread(){
public void run(){
Foo.dosome();
}
};
t1.start();
t2.start();
}
class Foo{
public synchronized static voiddosome(){
Thread t = Thread.currentThread();
System.out.println(t.getName()+":正在执行dosome方法...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t.getName()+":执行dosome方法完毕!");
}
}
静态方法中使用同步块时
class Foo{
public static void dosome(){
synchronized (Foo.class) {//静态块也指定当前类的类对象,获取方式:类名.class
Thread t =Thread.currentThread();
System.out.println(t.getName()+ ":正在执行dosome方法...");
try {
Thread.sleep(5000);
} catch (InterruptedExceptione) {
}
System.out.println(t.getName()+ ":执行dosome方法完毕!");
}
}
互斥锁
当多个线程执行不同的代码片段,但是这些代码片段之间不能同时运行时就要设置为互斥的。
使用synchronized锁定多个代码片段,并且指定的同步监视器是同一个时,这些代码片段之间就是互斥的。
public class SyncDemo4 {
public static void main(String[] args){
Boo boo = new Boo();
Thread t1 = new Thread(){
public void run(){
boo.methodA();
}
};
Thread t2 = new Thread(){
public void run(){
boo.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public synchronized void methodA(){
Thread t = Thread.currentThread();
System.out.println(t+":正在执行A方法...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t+":执行A方法完毕!");
}
public synchronized void methodB(){
//synchronized(this) {//只要锁对象相同,就与methodA方法代码互斥
Thread t =Thread.currentThread();
System.out.println(t + ":正在执行B方法...");
try {
Thread.sleep(5000);
} catch (InterruptedExceptione) {
}
System.out.println(t + ":执行B方法完毕!");
}
}
Synchronized原理分析
……