多线程访问同步方法的7种情况
前言
synchronized有两种用法:对象锁和类锁。
对象锁又分为方法锁(默认锁对象为this)和同步代码块锁。
类锁又分为修饰静态方法的锁和指定为class对象的锁。
类锁的本质是class对象的锁,Java类可能会有很多个对象,但是只有1个class对象。
1.两个线程同时访问一个对象的同步方法
public class SynchronizedObjectMethod3 implements Runnable {
static SynchronizedObjectMethod3 instance = new SynchronizedObjectMethod3();
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("finished");
}
@Override
public void run() {
method();
}
public synchronized void method(){
System.out.println("我的对象锁的方法修饰符形式,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
此时两个线程争抢同一把锁,故线程为串行执行.
结果为:
我的对象锁的方法修饰符形式,我叫Thread-0
Thread-0运行结束
我的对象锁的方法修饰符形式,我叫Thread-1
Thread-1运行结束
finished
2.两个线程访问两个对象的静态方法
public class SynchronizedObjectCodeBlock2 implements Runnable{
static SynchronizedObjectCodeBlock2 instance1 = new SynchronizedObjectCodeBlock2();
static SynchronizedObjectCodeBlock2 instance2 = new SynchronizedObjectCodeBlock2();
Object lock1 = new Object();
Object lock2 = new Object();
@Override
public void run() {
synchronized (this){
System.out.println("我是lock1. 我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +" lock1部分运行结束.");
}
// synchronized (lock2){
// System.out.println("我是lock2. 我叫" + Thread.currentThread().getName());
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() +" lock2部分运行结束.");
// }
}
public static void main(String[] args) {
Thread t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("finished");
}
}
此时两个线程争抢的是不同的锁,synchronized不起作用.
我是lock1. 我叫Thread-0
我是lock1. 我叫Thread-1
Thread-0 lock1部分运行结束.
Thread-1 lock1部分运行结束.
finished
3.两个线程访问的是synchronized的静态方法
public class SynchronizedClassStatic4 implements Runnable{
static SynchronizedClassStatic4 instance1 = new SynchronizedClassStatic4();
static SynchronizedClassStatic4 instance2 = new SynchronizedClassStatic4();
@Override
public void run() {
method();
}
public static synchronized void method(){
System.out.println("我是类锁的第一种形式:static形式.我叫" + 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(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while(t1.isAlive() || t2.isAlive()){
}
System.out.println("finished");
}
}
结果为:
我是类锁的第一种形式:static形式.我叫Thread-0
Thread-0运行结束.
我是类锁的第一种形式:static形式.我叫Thread-1
Thread-1运行结束.
finished
4.同时访问同步方法与非同步方法
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("finished");
}
}
一个方法加synchronized修饰不影响另一个方法的并发。非同步方法不受同步方法的影响。
我是加锁的方法.我叫Thread-0
我是没加锁的方法.我叫Thread-1
Thread-0运行结束
Thread-1运行结束
finished
5.访问同一个对象的不同普通同步方法
public class SynchronizedDifferentMethod7 implements Runnable{
static SynchronizedDifferentMethod7 instance = new SynchronizedDifferentMethod7();
@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("finished");
}
}
此时指认this对象作为锁,对于同一个实例来说,锁是相同的。
我是加锁的方法1.我叫Thread-0
Thread-0运行结束
我是加锁的方法2.我叫Thread-1
Thread-1运行结束
finished
6.同时访问静态synchronized和非静态synchronized方法
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("finished");
}
}
这两个方法可以并行执行.静态加锁的方法的锁是class对象,非静态加锁的方法的锁对象是this对象.这两个方法不是争抢同一把锁。
我是静态加锁的方法1.我叫Thread-0
我是非静态加锁的方法2.我叫Thread-1
Thread-0运行结束
Thread-1运行结束
finished
7.方法抛异常后,会释放锁
/**
* 方法抛异常后,会释放锁
* 展示不抛出异常前和抛出异常后的对比
* 一旦抛出了异常
* 第二个线程会立刻进入同步方法
* 意味着锁已经释放
*/
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("finished");
}
}
我是加锁的方法1.我叫Thread-0
Exception in thread "Thread-0" 我是加锁的方法2.我叫Thread-1
java.lang.RuntimeException
at com.interview.javabasic.thread.SynchronizedException9.method1(SynchronizedException9.java:29)
at com.interview.javabasic.thread.SynchronizedException9.run(SynchronizedException9.java:16)
at java.lang.Thread.run(Thread.java:748)
Thread-1运行结束
finished