版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38737992/article/details/89576078
synchronized 关键字用来同步“方法”或者“代码块”,可以实现原子性,可见性,有序性。采取互斥机制,即在同一时刻,只能有一个线程访问同步资源,串行的执行“方法”或者“代码块”。
缺点:缺点降低了线程的并发性;不能中断;多个锁交叉容易死锁。
1. 问题的引出
多个线程在共享一个数据的时候会出现问题,如下所示,多个线程共同访问一个变量。
package synchronizedStudy;
public class MyStudy implements Runnable {
private int count;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.print(Thread.currentThread().getName() + ": ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
}
public static void main(String args[]) {
MyStudy runn = new MyStudy();
Thread thread1 = new Thread(runn, "thread1");
Thread thread2 = new Thread(runn, "thread2");
Thread thread3 = new Thread(runn, "thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果如下所示,共享变量出现了重复值。
2. synchronized 关键字同步“代码块”解决问题
synchronized 关键字用来同步“代码块”,即在同一时刻,只能有一个线程访问同步资源,串行的执行“代码块”。
先声明一个静态常量对象:
public final static Object Mutex = new Object();
对应代码块加锁,这个代码块在同一时刻,只能有一个线程执行这段代码:
synchronized (Mutex) {
System.out.print(Thread.currentThread().getName() + ": ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
全部代码如下所示:
package synchronizedStudy;
public class MyStudy implements Runnable {
private int count;
public final static Object Mutex = new Object();
@Override
public void run() {
for (int i = 0; i < 5; i++) {
this.work();
}
}
public void work() {
synchronized (Mutex) {
System.out.print(Thread.currentThread().getName() + ": ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
}
public static void main(String args[]) {
MyStudy runn = new MyStudy();
Thread thread1 = new Thread(runn, "thread1");
Thread thread2 = new Thread(runn, "thread2");
Thread thread3 = new Thread(runn, "thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果:
3. synchronized 关键字同步“方法”解决问题
synchronized 关键字用来同步“方法”,即在同一时刻,只能有一个线程访问同步资源,串行的执行“方法”。
public synchronized void work() {
System.out.print(Thread.currentThread().getName() + ": ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
全部代码如下所示:
package synchronizedStudy;
public class MyStudy implements Runnable {
private int count;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
this.work();
}
}
public synchronized void work() {
System.out.print(Thread.currentThread().getName() + ": ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
public static void main(String args[]) {
MyStudy runn = new MyStudy();
Thread thread1 = new Thread(runn, "thread1");
Thread thread2 = new Thread(runn, "thread2");
Thread thread3 = new Thread(runn, "thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行截图:
4. 多个锁交叉容易死锁
如下所示,锁READ和锁WRITE交叉:
public void work() {
synchronized (READ) {
synchronized (WRITE) {
...
}
}
public void work1() {
synchronized (WRITE) {
synchronized (READ) {
...
}
}
全部代码:
package synchronizedStudy;
public class MyStudy implements Runnable {
private int count;
public final static Object READ = new Object();
public final static Object WRITE = new Object();
@Override
public void run() {
for (int i = 0; i < 5; i++) {
this.work();
this.work1();
}
}
public void work() {
synchronized (READ) {
synchronized (WRITE) {
System.out.print(Thread.currentThread().getName());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void work1() {
synchronized (WRITE) {
synchronized (READ) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String args[]) {
MyStudy runn = new MyStudy();
Thread thread1 = new Thread(runn, "thread1");
Thread thread2 = new Thread(runn, "thread2");
Thread thread3 = new Thread(runn, "thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果,发生了死锁: