多个线程 可以共享同一个进程中的资源
多线程对进程中的 公共变量 进行同时访问
如果不加锁的时候,有可能访问不到。
1 synchronize
本质 对具体对象的加锁(类锁:对类在虚拟机中的class对象的加锁)
对象锁://保证对象的原子性
- 同步块 加锁
- 方法 加锁
/**
*类说明:synchronized关键字的使用方法
*/
public class SynTest {
private long count =0;
private Object obj = new Object();//作为一个锁
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
/*用在同步块上*/
public void incCount(){
synchronized (obj){
count++;
}
}
/*用在方法上*/
public synchronized void incCount2(){
count++;
}
/*用在同步块上,但是锁的是当前类的对象实例*/
public void incCount3(){
synchronized (this){
count++;
}
}
//线程
private static class Count extends Thread{
private SynTest simplOper;
public Count(SynTest simplOper) {
this.simplOper = simplOper;
}
@Override
public void run() {
for(int i=0;i<10000;i++){
simplOper.incCount();//count = count+10000
}
}
}
public static void main(String[] args) throws InterruptedException {
SynTest simplOper = new SynTest();
//启动两个线程
Count count1 = new Count(simplOper);
Count count2 = new Count(simplOper);
count1.start();
count2.start();
Thread.sleep(50);
System.out.println(simplOper.count);//20000
}
}
2 volatile关键字,最轻量的同步机制
一写多读场景
import cn.enjoyedu.tools.SleepTools;
/**
* 类说明:演示Volatile的提供的可见性
*/
public class VolatileCase {
private static boolean ready; // private volatile static boolean ready;
private static int number;
private static class PrintThread extends Thread{
@Override
public void run() {
System.out.println("PrintThread is running.......");
while(!ready);
System.out.println("number = "+number);
}
}
public static void main(String[] args) {
new PrintThread().start();
SleepTools.second(1);
number = 51;
ready = true;
SleepTools.second(5);
System.out.println("main is ended!");
}
}
3 ThreadLocal的使用
线程的隔离 - spring 事物
每一个线程都有变量的副本 每个线程 有拥有自己的ThreadlocalMap (可以看做Map<Object,Object> 形式) 以实现线程的安全
等待和通知的标准范式
等待:
syn(对象){ //获得锁
while(条件不满足){
对象.wait(); //并释放对象锁
}
//业务逻辑
}
通知:
syn(对象){
// 业务逻辑 改变条件
//do sth ;
对象.notify/ notifyAll();
}//当syn中全部运行完 才会释放锁