线程同步代码块synchronized应用解析
当多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,成为线程安全问题。
线程同步
让多个线程实现先后访问共享资源,就解决了安全问题
线程同步的核心思想
加锁,把共享资源进行上锁,每次只能一个线程进入,访问完毕后解锁,然后其他线程才能进来。
同步代码块
synchronized(临界资源对象){
//原子操作
}
作用:把出现线程安全问题的核心代码给上锁
原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行
如果想要实现线程同步,需要不同的线程抢占同一个对象锁标记(对临界资源加锁)才能达到互斥目的,从而实现线程同步,数据安全。
线程执行过程中,遇到同步代码块,只有获取临界资源对象的锁标记才能执行同步代码块{}中的内容,并且将{}中所有的程序全部执行完,才能释放拥有的锁标记,如果一个线程试图获取锁标记时,使得锁标记被其他线程占用,则当前线程进入阻塞状态(Blocked),等待获取锁标记,只有获取了等待对象的锁标记并获取了cpu的时间片才能执行同步代码块{}中的内容。
【线程同步小demo】
public class Test {
public static void main(String[] args) throws InterruptedException {
String str = "呵呵";
String str1 = "嘿嘿";
Thread t1 = new ThreadA(str,"t1");
Thread t3 = new ThreadA(str1,"t3");
Thread t2 = new ThreadB(str,"t2");
t1.start();
t2.start();
t3.start();
t3.join();
t1.join();
t2.join();
}
}
class ThreadA extends Thread{
String str = null;
public ThreadA(String str,String name) {
super(name);
this.str = str;
}
public void run(){
synchronized (str) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("");
}
}
}
class ThreadB extends Thread{
String str = null;
public ThreadB(String str,String name) {
super(name);
this.str = str;
}
public void run(){
synchronized (str) {
System.out.println(Thread.currentThread().getName());
System.out.println("");
}
}
}
------------------------------------------
t1
t3
过了几秒后
t2
程序解析:
线程 t1 和线程 t2 内部的 str 指向的是同一个对象"呵呵",而线程 t3 内部的str指向的是"嘿嘿"。
程序开始运行时,调用 join() 方法后,t1 t2 t3 优先于main线程执行,t1 先抢到cpu时间片进行执行,遇到synchronized 同步代码块,获得str的 锁标记,此时"呵呵"锁标记被占,t1 进入休眠状态,释放cpu时间片但并不释放锁标记。
这时,哪怕 t2 获得了cpu时间片,t2 由于没有"呵呵"的锁标记,所以只能进入阻塞状态。
此时 t3 获得”嘿嘿"锁标记,进行执行,执行完毕后释放锁标记,t3 执行完毕。
t1 从睡眠中苏醒后执行完代码块,释放”呵呵“锁标记,然后 t2 才能占有”呵呵“锁标记进行后续代码执行。