synchronized(1)
概述
1.synchronized的作用
2.synchronized使用方式
3.synchronized导致的死锁
第1节 synchronized的作用
在并发编程中存在线程安全问题,主要原因有:
1.存在共享数据
2.多线程共同操作共享数据。
关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,实现线程安全。
第2节 synchronized使用方式
synchronized可以使用在代码块和方法中,根据使用的位置不同,可以有这些使用场景:
synchronized可以用在方法上也可以使用在代码块中,
使用在实例方法锁的是实例对象。
使用在静态方法锁的是类对象。
使用在代码块中也可以分为三种,具体的可以看上面的表格。
这里的需要注意的是:
如果锁的是类对象的话,尽管new多个实例对象,
但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系。
代码语言:javascript复制/**
* @Author: 超神的蜗牛
* @Date: 2019-07-22 19:53
* @Description: 多个线程访问同一个对象的同一个方法
*/
public class SynchronizedTest01 implements Runnable {
/**
* 共享资源
*/
static int counter = 0;
/**
* synchronized 修饰实例方法
*/
public synchronized void increase() {
for (int j = 0; j < 10; j ) {
System.out.println(Thread.currentThread().getName() "执行累加操作。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter ;
}
}
@Override
public void run() {
increase();
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest01 test = new SynchronizedTest01();
Thread t1 = new Thread(test, "线程1");
Thread t2 = new Thread(test, "线程2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter);
}
}
执行结果:
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程1执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
线程2执行累加操作。。。
20
代码语言:javascript复制/**
* @Author: 超神的蜗牛
* @Date: 2019-07-22 19:59
* @Description: 一个线程获取了该对象的锁之后,其他线程来访问其他synchronized实例方法现象
*/
public class SynchronizedTest02 {
/**
* 同步方法1
*/
public synchronized void method1() {
System.out.println("Method 1 started:t" TimeUtils.currentTime());
try {
System.out.println("Method 1 executed:t" TimeUtils.currentTime());
// sleep方法不会释放监视锁
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 ended:t" TimeUtils.currentTime());
}
/**
* 同步方法2
*/
public synchronized void method2() {
System.out.println("Method 2 started:t" TimeUtils.currentTime());
try {
System.out.println("Method 2 executed:t" TimeUtils.currentTime());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 ended:t" TimeUtils.currentTime());
}
public static void main(String[] args) {
final SynchronizedTest02 test = new SynchronizedTest02();
new Thread(() -> test.method1()).start();
new Thread(() -> test.method2()).start();
}
}
执行结果:
Method 1 started:2019-07-24 23:57:21
Method 1 executed:2019-07-24 23:57:21
Method 1 ended:2019-07-24 23:57:31
Method 2 started:2019-07-24 23:57:31
Method 2 executed:2019-07-24 23:57:31
Method 2 ended:2019-07-24 23:57:32
代码语言:javascript复制/**
* @Author: 超神的蜗牛
* @Date: 2019-07-22 20:19
* @Description: 一个线程获取了该对象的锁之后,其他线程来访问其他非synchronized实例方法现象
*/
public class SynchronizedTest03 {
/**
* 同步方法1
*/
public synchronized void method1() {
System.out.println("Method 1 started:t" TimeUtils.currentTime());
try {
System.out.println("Method 1 execute:t" TimeUtils.currentTime());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 ended:t" TimeUtils.currentTime());
}
/**
* 同步方法2
*/
public void method2() {
System.out.println("Method 2 started:t" TimeUtils.currentTime());
try {
System.out.println("Method 2 execute:t" TimeUtils.currentTime());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 ended:t" TimeUtils.currentTime());
}
public static void main(String[] args) {
final SynchronizedTest03 test = new SynchronizedTest03();
new Thread(() -> test.method1()).start();
new Thread(() -> test.method2()).start();
}
}
执行结果:
第3节 synchronized导致的死锁
代码语言:javascript复制/**
* @Author: 超神的蜗牛
* @Date: 2019-07-23 22:36
* @Description: synchronized造成的死锁
*
* 任何一个Java对象都可以充当一把锁
*
* 分别定义"A" 和 "B"两把锁
*
* 启动两个线程t1 和 t2
*
* 不管t1或者t2谁先获取到CPU使用权都会死锁(start()方法使线程进入可运行状态——具体参考之前的视频)
*
* 1.假设t1优先获取CPU使用权,进入运行态。线程t1获取到A锁后休眠2s(休眠不会释放锁),然后尝试获取B锁
* 随后t2获取CPU使用权,进入运行态。线程t2获取到B锁后休眠2s(休眠不会释放锁),然后尝试获取A锁
* 这时候t1休眠结束,t1尝试获取B锁,等待t2释放B锁
* 这时候t2休眠结束,t2尝试获取A锁,等待t1释放A锁
* t1和t2相互等待对方释放锁,此时造成死锁。
*
* 2.线程t2优先获取到CPU使用的情况与1类似。
*
*/
public class DeadLock {
/** A锁 */
private static String A = "A";
/** B锁 */
private static String B = "B";
public static void main(String[] args) {
new DeadLock().deadLock();
}
public void deadLock() {
/**
* 先获取A锁再获取B锁
*/
Thread t1 = new Thread(() -> {
synchronized (A) {
try {
// 获取A锁后休眠2s
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
// 获取B锁
System.out.println("thread1...");
}
}
});
/**
* 先获取B锁再获取A锁
*/
Thread t2 = new Thread(() -> {
synchronized (B) {
try {
// 获取B锁后休眠2s
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (A) {
System.out.println("thread2...");
}
}
});
t1.start();
t2.start();
}
}