synchronized 内置锁
线程开始运行,拥有自己的栈空间,就如同一个脚本一样,按照既定的代码一步一步地执行,直到终止。但是,每个运行中的线程,如果仅仅是孤立地运行,那么没有一点儿价值,或者说价值很少,如果多个线程能够相互配合完成工作,包括数据之间的共享,协同处理事情。这将会带来巨大的价值。
Java 支持多个线程同时访问一个对象或者对象的成员变量,但是多个线程同时访问同一个变量,会导致不可预料的结果。关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性,使多个线程访问同一个变量的结果正确,它又称为内置锁机制。
对象锁和类锁
对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的 class 对象上的。
private void incCount(){
synchronized (object){
count++;
}
}
private synchronized void incCountSyn(){
count++;
}
private synchronized static void incCountStaticSyn(){
count++;
}
volatile,最轻量的通信/同步机制
volatile 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某
个变量的值,这新值对其他线程来说是立即可见的。
不加 volatile 时,子线程无法感知主线程修改了 ready 的值,从而不会退出循环,而加了 volatile 后,子线程可以感知主线程修改了 ready 的值,迅速退出循环。
但是 volatile 不能保证数据在多个线程下同时写时的线程安全,volatile 最适用的场景:一个线程写,多个线程读。
代码示例
public class VolInstance {
private static boolean ready;
private static int num;
public static void main(String[] args) throws InterruptedException {
new PrintThread().start();
Thread.sleep(1000);
num = 51;
//Thread.sleep(1000);
ready = true;
Thread.sleep(3000);
System.out.println("main is ended");
}
private static class PrintThread extends Thread{
public void run(){
while (!ready){
}
System.out.println("PrintThread end! num = "+num);
}
}
}
执行结果:主线程已经结束,而PrintThread线程无法感知ready修改,从而不会退出循环
但是在循环中增加print打印后
private static class PrintThread extends Thread{
public void run(){
while (!ready){
System.out.println("num = "+num);
}
System.out.println("PrintThread end! num = "+num);
}
}
执行结果:PrintThread子线程竟然感知到主线程修改了 ready 的值,退出了循环。其实是print语句操作刷新了子线程的本地内存得到了num和ready的值
证明:将代码修改如下,在给num赋值以后,让主线程睡眠1s,修改PrintThread子线程为得到num为51的值以后不再print
public class VolInstance {
private static boolean ready;
private static int num;
public static void main(String[] args) throws InterruptedException {
new PrintThread().start();
Thread.sleep(1000);
num = 51;
Thread.sleep(1000);
ready = true;
Thread.sleep(3000);
System.out.println("main is ended");
}
private static class PrintThread extends Thread{
public void run(){
while (!ready){
if(num!=51){
System.out.println("num = "+num);
}
}
System.out.println("PrintThread end! num = "+num);
}
}
}
执行结果:PrintThread子线程因为print语句得到num的值以后不再打印,后无法感知ready修改,从而不会退出循环
给ready加了volatile后
private volatile static boolean ready;
执行结果:子线程可以感知主线程修改了 ready 的值,迅速退出循环。