package com.hjx.thread;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class ForSync {
/**
* synchronized,可重入锁,一个同步方法可以调另一个方法
* synchronized的底层实现
* synchronized(object)如果这个对象是静态的,那么是不是跟synchronized(T.class)一样的?
* 锁升级:当第一个线程进入同步方法的时候,是不加锁的,就是偏向锁;如果有线程争抢,就升级为自旋锁,
* 自旋锁:自旋10次,就相当于一个while(true),这个线程一直在自旋,10次过后还拿不到锁,升级为重量级锁
* 重量级锁:去操作系统申请资源,处于阻塞状态
* 自旋锁做了什么?
* 自旋锁就是让线程处于自旋状态,不放弃cpu的时间片,多次尝试获取锁;而非自旋锁,就直接让线程处于休眠状态,等待锁释放,在唤醒线程,这样会耗费资源,代价大
* Atomic和lock都用自旋锁,在用户态,占cpu
* 执行时间短,枷锁代码,线程数少用自旋锁,反之用系统锁
* */
/**
* volatile 保证线程可见性: 1.每个线程有自己的工作空间,还有共享内存,比如堆内存 2.利用了cpu的缓存一致性原理,volatile保证工作空间变量的更改更新到共享内存对其他线程保持可见
*/
volatile boolean running = true;
@Test
public void visibility() {
ForSync sync = new ForSync();
new Thread(sync::m, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
sync.running = false;
}
public void m() {
System.out.println("start");
while (running) {
}
System.out.println("end");
}
/**
* 2. 禁止指令重排序: 单例模式双重检验锁 比如 :new一个对象,分为申请内存空间,初始化,再将值赋值给引用
*/
public static volatile ForSync forSync;
volatile int count = 0;
public static ForSync getForSync() {
if (forSync == null) {
synchronized (ForSync.class) {
if (forSync == null) {
forSync = new ForSync();
}
}
}
return forSync;
}
@Test
public void Reorder() {
for (int i = 0; i < 100; i++) {
count++;
new Thread(new Runnable() {
@Override
public void run() {
System.out
.println(Thread.currentThread().getName() + "---" + ForSync.getForSync().hashCode());
}
}).start();
}
System.out.println(count);
}
/**
* 3. volatile不能保证原子性 count是可见的,但count++不是原子性的,比如count由0变为1,这时其它几个线程都能读到1,都在1的基础上++ 所以不能保证线程安全
*/
volatile int value = 0;
void t() {
for (int i = 0; i < 100; i++) {
value++;
}
}
@Test
public void atomic() {
ForSync forSync = new ForSync();
for (int i = 0; i < 10; i++) {
new Thread(forSync::t,"t"+i).start();
}
System.out.println(forSync.value);
}
}
sync&volatile
最新推荐文章于 2021-11-15 18:35:32 发布