文章目录
线程安全和线程同步及时读取问题
线程安全问题
在多个线程同时操作同一个对象(变量)的时候会在自己的栈内存里面进行,出现这样的情况的时候,如果线程没有及时的把自己操作之后的结果,同步到堆内存里面,就会导致最后的变量并不是我们希望得到的操作之后的结果,因此就发生了线程不安全的情况。为了解决这个问题,我们需要对于变量和线程进行同步。
而解决这个问题的思路就是锁,即当一个线程对于一个变量进行操作的时候,我们可以利用锁把这个变量锁起来,这样就可以保证一次只有一个线程在操作某个变量,进而保证了栈内存里面如果变量发生了改变,会把这个信息及时的更新到堆内存里面,这样所有的线程就会知道这个信息,进而保障了线程的安全问题。而之所以叫做synchronized(同步)也是因为这样的设置会导致没有抢占到资源的线程进入堵塞的状态,而在这个过程中实现了线程之间信息的同步。
线程同步及时更新读取问题
通常,锁的使用适合在存在有写和更改数据的场景里面,而只存在读写的场景的时候,数据之间的及时看见和更新,可以使用volatile来解决。这个一般存在的情况是,线程都会执行某种任务,线程内部可能是一个死循环,但是这个循环内的某个变量会需要及时的更新(可能其他的线程会对这个变量进行更改)这种情况下,我们的线程没有去修改任何的变量,但是需要及时的知晓变量的变化,使用锁的话,可能效率比较低,这个时候,就可以使用volatile解决这个问题。
线程安全问题的解决办法:锁
synchronized锁住某个变量(被操作的对象)
假如我们的线程都想要去操作Task里面的num这个变量,那么可以直接在里面写操作的时候,就把这个变量给锁住。其中锁后面的变量一样的,就是一把锁,一个时间内,持有这种锁的线程才能运行。锁里面是什么对象不重要,重要的是竞争的线程之间,分享的都是这同一个对象。
class Task{
int num;
public void add(){
synchronized(this){
num ++;}
}
public void multiple(){
synchronized(this){
num *= num;}
}
synchronized锁住某个对象的方法
这个直接在对象的方法前面加上synchronized关键词就ok啦,就像test做的那样
public class Test {
public synchronized void test(Task obj){
for (int i = 0; i < 20000; i++) {
obj.num++;
}
}
public static void main(String[] args) {
Test t = new Test();
Task ta = new Task();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (