Volatile 关键字
作用:
Volatile 关键字是多线程下,最小轻量级的同步机制。
过程:
首先Volatile 修饰的成员变量应该是多个线程共享的资源,每个线程在访问共享变量的时候,线程的工作内存中都会存有这个变量的一个拷贝,变量本身还是保存在共享内存中。对这个变量的访问必须从共享内存刷新一次。最新的修改写回共享内存,保证了字段的可见性,但是并没有保证操作对该变量操作的原子性。(多线程下原子性:指的是原子操作的最小粒子,指不可被中断的一个或一系列操作)
synchronized 关键字 修饰方法和修饰对象的区别(实践是检验真理的唯一标准)
首先是synchronized 修饰方法时,运行main 方法看到的效果是 doSomething 和 getSomething 基本上是同步执行的。 由此可见 synchroized 修饰的方法时,锁的是对象本身。
package com.chen.springboot.thread.signal;
import java.util.concurrent.CountDownLatch;
public class Entiry {
private static volatile Entiry entiry; // 创建一个单列实例
private static CountDownLatch countDownLatch = new CountDownLatch(1); // 发令枪保证 多线程并发
public static Entiry instanceEntity(){ // 懒汉模式创建 单列
if(entiry==null){
synchronized (Entiry.class){
if(entiry==null){
entiry = new Entiry();
}
}
}
return entiry;
}
public synchronized void doSomething(String index){ //两个同步方法
System.out.println(index+"获取到了 doSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void getSomething(String idex){ //两个同步方法
System.out.println(idex+"获取到了 getSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int i=0;i<20;i++){
Thread t = new Thread(new CRunnable(i));
t.start();
}
countDownLatch.countDown();
}
static class CRunnable implements Runnable{
private Integer index;
public CRunnable(Integer index) {
this.index = index;
}
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Entiry entiry = Entiry.instanceEntity();
//多线程运行 为了区别 让一半的线程执行同步方法A 另一半的线程执行同步方法B
if(index%2==0){
entiry.doSomething(String.valueOf(index));
}else {
entiry.getSomething(String.valueOf(index));
}
}
}
}
synchronized 修饰this,效果和锁方法是一样的。
package com.chen.springboot.thread.signal;
import java.util.concurrent.CountDownLatch;
public class Entiry {
private static volatile Entiry entiry; // 创建一个单列实例
private static CountDownLatch countDownLatch = new CountDownLatch(1); // 发令枪保证 多线程并发
public static Entiry instanceEntity(){ // 懒汉模式创建 单列
if(entiry==null){
synchronized (Entiry.class){
if(entiry==null){
entiry = new Entiry();
}
}
}
return entiry;
}
public void doSomething(String index){ //两个同步方法
synchronized (this){
System.out.println(index+"获取到了 doSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void getSomething(String idex){ //两个同步方法
synchronized (this){
System.out.println(idex+"获取到了 getSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for(int i=0;i<20;i++){
Thread t = new Thread(new CRunnable(i));
t.start();
}
countDownLatch.countDown();
}
static class CRunnable implements Runnable{
private Integer index;
public CRunnable(Integer index) {
this.index = index;
}
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Entiry entiry = Entiry.instanceEntity();
//多线程运行 为了区别 让一半的线程执行同步方法A 另一半的线程执行同步方法B
if(index%2==0){
entiry.doSomething(String.valueOf(index));
}else {
entiry.getSomething(String.valueOf(index));
}
}
}
}
区别:锁方法时是将整个方法体都被锁住,对于有些不需要执行同步的步骤来说是这样锁是不合理的,所以一般都用synchronized关键字赖控制锁的粒度。
锁如果加载静态方法或者时静态类时,效果是什么样呢?
两个同步方法都加了锁住了类,单列实例还是原来的效果。多个实现类时发现效果也是一样的。可见锁住类时,不管多个实现类执行锁类的方法时都是同步的。原因是:多个实现类共享一个class对象。
public void doSomething(String index){ //两个同步方法
synchronized (Entiry.class){
System.out.println(index+"获取到了 doSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void getSomething(String idex){ //两个同步方法
synchronized (Entiry.class){
System.out.println(idex+"获取到了 getSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
当synchronized 关键字锁静态方法时,效果也是一样的这就可以进一步证明静态方法是属于累的,跟实例没有关系
public static synchronized void doSomething(String index){ //两个同步方法
System.out.println(index+"获取到了 doSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getSomething(String idex){ //两个同步方法
System.out.println(idex+"获取到了 getSomething");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}