1 两个线程同时访问一个对象的同步方法
synchronized
起作用
2 两个线程访问的是两个对象的同步方法
synchronized
不起作用
3 两个线程访问的是 synchronized
的静态方法
synchronized
起作用
4 同时访问同步方法和非同步方法
synchronized
不会影响其他方法,即非同步方法不受影响
/**
* @Description 同步方法和非同步方法
* @Author tzb
* @Date 2021/1/8 15:52
* @Version 1.0
**/
public class SynchronizedYesAndNo6 implements Runnable {
static SynchronizedYesAndNo6 instance = new SynchronizedYesAndNo6();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")) {
method1();
} else {
method2();
}
}
public synchronized void method1() {
System.out.println("我是加锁的方法,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public void method2() {
System.out.println("我是没有加锁的方法,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("运行结束");
}
}
5 访问同一个对象的不同的普通同步方法
- 两个
synchronized
拿到的都是 instance 的 this - 程序串行运行
/**
* @Description 同时访问一个类的不同的普通同步方法
* @Author tzb
* @Date 2021/1/8 16:53
* @Version 1.0
**/
public class SynchronizedDiffMethod7 implements Runnable {
static SynchronizedDiffMethod7 instance = new SynchronizedDiffMethod7();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")) {
method1();
} else {
method2();
}
}
public synchronized void method1() {
System.out.println("我是加锁的方法1,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public synchronized void method2() {
System.out.println("我是加锁的方法2,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("运行结束");
}
}
6 同时访问静态 synchronized
和 非静态 synchroinzed
方法
- 拿到的锁是不一样的,可以同时运行
public class SynchronizedStaticAndNormal8 implements Runnable {
static SynchronizedStaticAndNormal8 instance = new SynchronizedStaticAndNormal8();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")) {
method1();
} else {
method2();
}
}
public synchronized static void method1() {
System.out.println("我是静态加锁的方法1,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public synchronized void method2() {
System.out.println("我是非静态加锁的方法2,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("运行结束");
}
}
7 方法抛出异常后,会释放锁
一旦抛出了异常,第二个线程会立刻进入同步方法,意味着锁已经释放
/**
* @Description 方法抛出异常,释放锁
* @Author tzb
* @Date 2021/1/8 17:07
* @Version 1.0
**/
public class SynchronizedException9 implements Runnable {
static SynchronizedException9 instance = new SynchronizedException9();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")) {
method1();
} else {
method2();
}
}
public synchronized void method1() {
System.out.println("我是加锁的方法1,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 不要求强制捕获
throw new RuntimeException();
//System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public synchronized void method2() {
System.out.println("我是加锁的方法2,我叫 " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("运行结束");
}
}
8 7种情况的总结:核心思想
- 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(情况1、5)
- 每个实例都对应有自己的一把锁,不同实例之间互不影响。例外:锁对象是
*.class
以及synchronized
修饰的是static
方法的时候,所有的对象共用同一把类锁。(情况2、3、4、6) - 无论方法正常执行完毕或者抛出异常,都会释放锁
一个被synchronized
修饰的方法调用了没有被同步修饰的方法还是线程安全的么?
- 不是线程安全了,因为调用的那个方法没有被修饰,其本身是可以被多个线程同时调用的