为什么线程需要用锁:
1.1介绍:
在多线程环境中,当多个线程同时访问和修改共享资源时,如果没有适当的同步机制,就可能导致数据竞争。数据竞争是指多个线程同时访问和修改同一资源,导致数据的不一致和错误。为了解决这个问题,需要使用加锁技术,如互斥锁、读写锁、递归锁等,来确保对共享资源的访问是顺序的或排他的。加锁可以防止多个线程同时修改同一数据,从而避免数据的不一致和错误。
此外,加锁还可以解决不同线程的子步骤有顺序关联性的问题。有时候,一个线程的执行顺序并不等同于程序的执行顺序,因为CPU和编译器可能会对代码进行优化,打乱代码的执行顺序。通过加锁,可以确保线程按照特定的顺序执行,从而保证程序的正确性。
总的来说,加锁是多线程编程中不可或缺的一部分,它确保了线程安全地访问和修改共享资源,避免了数据竞争和执行顺序的问题,从而保证了程序的正确性和数据的完整性。
总结:简单来说就是如果不加锁,可能会发生当前线程读到了其他线程的数据。锁可以让一段代码执行完再去执行其他线程
1.2示例:
我们来看看一个使用多线程的例子:(打印当前线程的内容)
public class ThreadTest {
public String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
threadTest.setContent("线程"+Thread.currentThread().getName());
System.out.println(ThreadTest.class.getName() + "---" + Thread.currentThread().getName() +"--->"+threadTest.getContent());
}
});
thread.setName("线程"+i);
thread.start();
}
}
}
显示结果:
从结果中,我们会很明显的发现出现了线程之间发生了错乱读取。
1.3使用synchronized
package com.day08.zl;
public class ThreadTest {
public String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (ThreadTest.class){
threadTest.setContent("线程" + Thread.currentThread().getName());
System.out.println(ThreadTest.class.getName() + "---" + Thread.currentThread().getName() + "--->" + threadTest.getContent());
}
}
});
thread.setName("线程"+i);
thread.start();
}
}
}
我们会发现,线程错读的现象消失了。
1.4ThreadLocal
除了synchronized之外,我们也可以使用更优的ThreadLocal来解决:
public class ThreadLocalTest {
public ThreadLocal<String> threadLocal = new ThreadLocal<>();
public String getContent() {
return threadLocal.get();
}
public void setContent(String content) {
threadLocal.set(content);
}
public static void main(String[] args) {
ThreadLocalTest threadLocalTest = new ThreadLocalTest();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
threadLocalTest.setContent("线程"+Thread.currentThread().getName());
System.out.println(ThreadLocalTest.class.getName() + "---" + Thread.currentThread().getName() +"--->"+threadLocalTest.getContent());
}
});
thread.setName("线程"+i);
thread.start();
}
}
}