java基础 关于线程安全

本文详细解析了线程安全的两大核心问题:变量安全与线程同步,并提供了多种解决方案,包括使用局部变量、ThreadLocal及同步锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程安全的本质体现在两个方面,

  A变量安全:多线程同时运行一段代码

  B线程同步:一个线程还没执行完,另一个线程又进来接着执行。

 看个简单的例子。

Java代码
  1. public class ThreadSafe implements java.lang.Runnable { 
  2.      
  3.     int num = 1
  4.     public void run() { 
  5.         for (int i = 0; i < 3; i++) { 
  6.             num = num + 1
  7.             try
  8.                 Thread.sleep(2000); 
  9.             } catch (InterruptedException e) { 
  10.                 e.printStackTrace(); 
  11.             } 
  12.             System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); 
  13.         } 
  14.     } 
  15.  
public class ThreadSafe implements java.lang.Runnable {
int num = 1;
public void run() {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
 
TestMan.java 写道
package com.java.thread.test;

public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}

}

运行结果

num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------5
num is value +===thread1---------6
num is value +===thread1---------7
num is value +===thread2---------7

很明显是错误的,应为两个线程共享同一个变量。这里就是变量的安全问题。

解决办法:

1抛弃单实例,多线程的方式,用多实例,多线程的方式,这样就和单线程是一个样了,不会出错,但是是最接近传统的编程模式

2不要用类的实例变量,经可能把变量封装到方法内部。

1类的解决办法的代码。

Java代码
  1. public class TestMan { 
  2.     public static void main(String[] args) { 
  3.         Runnable safe=new ThreadSafe(); 
  4.         Runnable safe2=new ThreadSafe(); 
  5.         Thread thread1=new Thread(safe,"thread1"); 
  6.         Thread thread2=new Thread(safe2,"thread2"); 
  7.         thread1.start(); 
  8.         thread2.start(); 
  9.     } 
  10.  
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Runnable safe2=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe2,"thread2");
thread1.start();
thread2.start();
}
}
 

运行结果

num is value +===thread1---------2
num is value +===thread2---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
2类解决办法的代码

Java代码
  1. public class ThreadSafe implements java.lang.Runnable { 
  2.      
  3.     public void run() { 
  4.         int num = 1
  5.         for (int i = 0; i < 3; i++) { 
  6.             num = num + 1
  7.             try
  8.                 Thread.sleep(2000); 
  9.             } catch (InterruptedException e) { 
  10.                 e.printStackTrace(); 
  11.             } 
  12.             System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); 
  13.         } 
  14.     } 
  15.  
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
 
Java代码
  1. public class TestMan { 
  2.     public static void main(String[] args) { 
  3.         Runnable safe=new ThreadSafe(); 
  4.  
  5.         Thread thread1=new Thread(safe,"thread1"); 
  6.         Thread thread2=new Thread(safe,"thread2"); 
  7.         thread1.start(); 
  8.         thread2.start(); 
  9.     } 
  10.  
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

运行结果

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4

这两种办法,比较推荐适用第二个办法,就是把变量经可能的封装到风发内部,这样他们就是线程的私有变量了。另外,从jdk1.2后,推出了 threadlocal 对象,它作为线程的一个局部变量,可以为每个线程创建一个副本,用来保存每个线程的属性,各是各的,互不干扰。单每个 threadlocal变量只能保存一个变量,假如有多个变量要保存,那么就要写多个threadlocal对象。

我们把代码改写一下。

Java代码
  1. public class ThreadSafe implements java.lang.Runnable { 
  2.     ThreadLocal<Integer> local=new ThreadLocal<Integer>(); 
  3.     public void run() { 
  4.         for (int i = 0; i < 3; i++) { 
  5.             if(local.get()==null){ 
  6.                 local.set(new Integer(1)); 
  7.             } 
  8.             int num=local.get().intValue(); 
  9.             num=num+1
  10.             local.set(new Integer(num)); 
  11.             try
  12.                 Thread.sleep(2000); 
  13.             } catch (InterruptedException e) { 
  14.                 e.printStackTrace(); 
  15.             } 
  16.             System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue()); 
  17.         } 
  18.     } 
  19.  
public class ThreadSafe implements java.lang.Runnable {
ThreadLocal<Integer> local=new ThreadLocal<Integer>();
public void run() {
for (int i = 0; i < 3; i++) {
if(local.get()==null){
local.set(new Integer(1));
}
int num=local.get().intValue();
num=num+1;
local.set(new Integer(num));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue());
}
}
}
 
Java代码
  1. public class TestMan { 
  2.     public static void main(String[] args) { 
  3.         Runnable safe=new ThreadSafe(); 
  4.         Thread thread1=new Thread(safe,"thread1"); 
  5.         Thread thread2=new Thread(safe,"thread2"); 
  6.         thread1.start(); 
  7.         thread2.start(); 
  8.     } 
  9.  
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

运行结果

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4

结果是一样的,所以这里变量安全有3个办法可以解决。

然后在说说线程的同步的问题。我们看上面的运行结果。

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4

就 可以看出他们不是线程同步的,是thread1和thread2在交替执行的。在有些情况下,要求一段代码在运行的过程中是一个不可分割的实体,就是原子的。就是说当已经有线程在执行这段代码的时候,其他的线程必须等待他执行完毕后才能竟来执行,这就是所谓的线程同步。

java通过同步锁来执行线程的同步和等待,也就是说,要不间断执行的代码需要放在synchronized关键字标识的代码块中。可以用来修饰代码块,也可以修饰方法。

Java代码
  1. public class ThreadSafe implements java.lang.Runnable{ 
  2.     public synchronized void run() { 
  3.         int num = 1
  4.         for (int i = 0; i < 3; i++) { 
  5.             num = num + 1
  6.             try
  7.                 Thread.sleep(2000); 
  8.             } catch (InterruptedException e) { 
  9.                 e.printStackTrace(); 
  10.             } 
  11.             System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); 
  12.         } 
  13.     } 
  14.  
  15.  
public class ThreadSafe implements java.lang.Runnable{
public synchronized void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
 
Java代码
  1. public class TestMan { 
  2.     public static void main(String[] args) { 
  3.         Runnable safe=new ThreadSafe(); 
  4.         Thread thread1=new Thread(safe,"thread1"); 
  5.         Thread thread2=new Thread(safe,"thread2"); 
  6.         thread1.start(); 
  7.         thread2.start(); 
  8.     } 
  9.  
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

运行结果

um is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread1---------4
num is value +===thread2---------2
num is value +===thread2---------3
num is value +===thread2---------4

可以看到thread1运行结束后thread2才开始运行的。代码还可以这么写

Java代码
  1. public class ThreadSafe implements java.lang.Runnable { 
  2.     public void run() { 
  3.         int num = 1
  4.         synchronized (this) { 
  5.             for (int i = 0; i < 3; i++) { 
  6.                 num = num + 1
  7.                 try
  8.                     Thread.sleep(2000); 
  9.                 } catch (InterruptedException e) { 
  10.                     e.printStackTrace(); 
  11.                 } 
  12.                 System.out.println("num is value +===" 
  13.                         + Thread.currentThread().getName() + "---------" + num); 
  14.             } 
  15.         } 
  16.     } 
  17.  
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
synchronized (this) {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="
+ Thread.currentThread().getName() + "---------" + num);
}
}
}
}
 

在启用同步锁机制以后,需要避免

1无线等待,,线程B等待线程A执行完毕,然后线程A确进入了死循环。

2循环等待:两个线程相互调用,都要求要同步执行,这个时候就先会循环等待,我等你执行,你也在等我执行,这个时候就死锁了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值