synchronized同步代码块可以锁定任意数据,运行时类,实例对象,成员变量都可以,我们来看不同的数据类型对应的代码。
(1)运行时类
运行时类在内存中只有一份,即线程同步。
package com.southwind.thread;
public class SynchronizedTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
for (int i = 1; i <= 5; i++) {
new Thread(myRunnable,"线程"+i).start();
}
}
}
class MyRunnable implements Runnable{
private int num = 0;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (MyRunnable.class) {
num++;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
}运行结果如图。

(2)实例对象
实例对象的创建写在for循环以外,则内存中只有一份实例对象,线程同步。
package com.southwind.thread;
public class SynchronizedTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
for (int i = 1; i <= 5; i++) {
new Thread(myRunnable,"线程"+i).start();
}
}
}
class MyRunnable implements Runnable{
private int num = 0;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (this) {
num++;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
}运行结果如图。

实例对象的创建写在for循环内部,则内存中有多份实例对象,线程异步。
package com.southwind.thread;
public class SynchronizedTest {
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable,"线程"+i).start();
}
}
}
class MyRunnable implements Runnable{
private int num = 0;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (this) {
num++;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
}运行结果如图。

(2.1)实例对象

(3)成员变量
内存中成员变量的个数是一个还是多个,是通过调用equals()方法来判断的,如果equals()方法返回true,表示两个变量相等,内存中只有一份,如果equals()方法返回false,表示两个变量不相等,内存中有多份。
package com.southwind.thread;
public class SynchronizedTest {
public static void main(String[] args) {
Object obj = new Object();
MyRunnable myRunnable = new MyRunnable(obj);
Object o1 = myRunnable.obj;
for (int i = 1; i <= 5; i++) {
myRunnable.obj = new Object();
System.out.println(myRunnable.obj.equals(o1));
o1 = myRunnable.obj;
new Thread(myRunnable,"线程"+i).start();
}
}
}
class MyRunnable implements Runnable{
private int num = 0;
public Object obj;
public MyRunnable(Object obj) {
// TODO Auto-generated constructor stub
this.obj = obj;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (obj) {
num++;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
}上述代码中每次循环创建线程对象时,都会重新给MyRunnable的成员变量obj赋值,所以成员变量是多个,equals方法返回false,线程异步。
运行结果如图。
略。。。
修改代码,去掉myRunnable.obj = new Object();
package com.southwind.thread;
public class SynchronizedTest {
public static void main(String[] args) {
Object obj = new Object();
MyRunnable myRunnable = new MyRunnable(obj);
Object o1 = myRunnable.obj;
for (int i = 1; i <= 5; i++) {
System.out.println(myRunnable.obj.equals(o1));
o1 = myRunnable.obj;
new Thread(myRunnable,"线程"+i).start();
}
}
}
class MyRunnable implements Runnable{
private int num = 0;
public Object obj;
public MyRunnable(Object obj) {
// TODO Auto-generated constructor stub
this.obj = obj;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (obj) {
num++;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
}每次循环创建线程对象时,没有重新给MyRunnable的成员变量obj赋值,所以成员变量是一个,equals方法返回true,线程同步。
运行结果如图。

参考来源:https://cloud.tencent.com/developer/article/1355674
下面参考:https://www.bilibili.com/video/av45946533/?p=31
(4)静态方法 锁的是这个类的所有对象实例调用者
package com.mmall.practice.example.sync;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class SynchronizedExample2 {
// 修饰一个静态的方法
// 其作用的范围是整个静态方法,作用的对象是这个类的所有对象
public static synchronized void test1() {
for (int i = 0; i < 10; i++) {
log.info("test1 - {}", i);
}
}
// 修饰一个类,
// 其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
public static void test2() {
synchronized (SynchronizedExample2.class) {
for (int i = 0; i < 10; i++) {
log.info("test2 - {}", i);
}
}
}
public static void main(String[] args) {
SynchronizedExample2 example1 = new SynchronizedExample2();
SynchronizedExample2 example2 = new SynchronizedExample2();
ExecutorService exec = Executors.newCachedThreadPool();
// public static synchronized void test1() 其作用的范围是整个静态方法,加锁的对象是这个类的所有对象example1,example2
// example1.test1();和 example2.test1();是同步執行的只有其中一个执行完,另一个才会执行
exec.execute(() -> {
try {
example1.test1();
} catch (Exception e) {
log.error("exception1", e);
}
});
exec.execute(() -> {
try {
example2.test1();
} catch (Exception e) {
log.error("exception2", e);
}
});
// synchronized (SynchronizedExample2.class) 其作用的范围是整个静态方法,加锁的对象是这个类的所有对象example1,example2
exec.execute(() -> {
try {
example1.test2();
} catch (Exception e) {
log.error("exception1", e);
}
});
exec.execute(() -> {
try {
example2.test2();
} catch (Exception e) {
log.error("exception2", e);
}
});
exec.shutdown();
}
}