(1)内置锁
(2)互斥锁
(3)synchronized修饰普通方法
public class SyncDemo {
public synchronized void exampleOut(){
try {
Thread.sleep(5000L);
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
long uptime = runtimeMXBean.getUptime();
System.out.println(Thread.currentThread().getName()+"-线程运行时长:"+uptime+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SyncDemo syncDemo1 = new SyncDemo();
SyncDemo syncDemo2 = new SyncDemo();
new Thread(() -> {
syncDemo1.exampleOut();
}).start();
new Thread(() -> {
syncDemo2.exampleOut();
}).start();
}

public static void main(String[] args) {
SyncDemo syncDemo1 = new SyncDemo();
SyncDemo syncDemo2 = new SyncDemo();
new Thread(() -> {
syncDemo1.exampleOut();
}).start();
new Thread(() -> {
syncDemo1.exampleOut();
}).start();
}

(4)synchronized修饰静态方法
public class SyncDemo {
public static synchronized void staticOut(){
try {
Thread.sleep(5000L);
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
long uptime = runtimeMXBean.getUptime();
System.out.println(Thread.currentThread().getName()+"-线程运行时长:"+uptime+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SyncDemo syncDemo1 = new SyncDemo();
SyncDemo syncDemo2 = new SyncDemo();
new Thread(() -> {
syncDemo1.staticOut();
}).start();
new Thread(() -> {
syncDemo2.staticOut();
}).start();
}

(5)synchronized修饰代码块
public class SyncDemo {
private Object lock = new Object();
public void blockOut(){
try {
Thread.sleep(5000L);
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
long uptime = runtimeMXBean.getUptime();
System.out.println(Thread.currentThread().getName()+"-线程运行时长:"+uptime+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SyncDemo syncDemo1 = new SyncDemo();
SyncDemo syncDemo2 = new SyncDemo();
new Thread(() -> {
syncDemo1.blockOut();
}).start();
new Thread(() -> {
syncDemo2.blockOut();
}).start();
}

public static void main(String[] args) {
SyncDemo syncDemo1 = new SyncDemo();
SyncDemo syncDemo2 = new SyncDemo();
new Thread(() -> {
syncDemo1.blockOut();
}).start();
new Thread(() -> {
syncDemo1.blockOut();
}).start();
}

(1)volatile关键字的作用
(2)为什么会出现脏读
(3)volatile案例实战
public class VolatileDemo {
private volatile boolean flag = false;
public void work(){
while (!flag) {
System.out.println("线程开始工作");
}
}
public void down(){
flag = true;
System.out.println("线程停止工作");
}
public static void main(String[] args) {
VolatileDemo work = new VolatileDemo();
new Thread(work::work).start();
new Thread(work::work).start();
new Thread(work::down).start();
new Thread(work::work).start();
new Thread(work::work).start();
}
}


(4)volatile只能保证变量的可见性,不能保证对volatile变量操作的原子性
public class VolatileDemo {
private volatile int num = 0;
//执行方法加上synchronized
public synchronized void addNum(){
num++;
}
//执行方法加上synchronized
public synchronized int getNum(){
return num;
}
public static void main(String[] args) {
VolatileDemo volatileDemo = new VolatileDemo();
new Thread(()->{
for (int i = 0; i < 1000; i++) {
volatileDemo.addNum();
}
System.out.println(volatileDemo.getNum());
}).start();
new Thread(()->{
for (int i = 0; i < 2000; i++) {
volatileDemo.addNum();
}
System.out.println(volatileDemo.getNum());
}).start();
new Thread(()->{
for (int i = 0; i < 3000; i++) {
volatileDemo.addNum();
}
System.out.println(volatileDemo.getNum());
}).start();
}
}


(1)理解happens-before
(2)happens-before六大规则
class VolatileExample{
int a=0;
volatile boolean flag=false;
public void writer(){
a=1; // 操作1
flag=true; // 操作2
}
public void reader(){
if(flag){ // 操作3
int i=a; // 操作4
//这里i会是多少呢?
}
}
}
程序顺序规则
volatile变量规则
传递性规则
管程中锁的规则
synchronized(this){
if(this.x < 12){
this.x = 12;
}
}
//根据管程中锁的规则,线程A执行完成后x会变成12,执行完释放锁,线程B进入代码块的时候,能够看到线程A对x的操作,也就睡说B看到的x值为12。
public class StartDemo {
private static int num = 0;
public static void main(String[] args) {
Thread A = new Thread(()->{
Thread B = new Thread(()->{
System.out.println("B线程中读取num:"+num); //操作2
});
num = 1; //操作1
B.start();
});
A.start();
}
}
//根据线程start规则,1 happens-before 2,线程A对共享变量a=1的操作对于线程B是可见的。

public class JoinDemo {
private static int num = 0;
public static void main(String[] args) {
Thread A = new Thread(()->{
Thread B = new Thread(()->{
num = 2;
});
num = 1;
B.start();
try {
B.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A线程中读取num:"+num);
});
A.start();
}
}

(1)线程安全性问题成因
(2)如何避免线程安全性问题