知识点清单
| 原子性 |
提供互斥访问,同一时刻只能有一个线程对数据进行操作 |
| 原子操作 | 不能被中断的一个或一系列操作具有原子性 |
| 临界区 | 是指锁和解锁之间的代码块,任何时候临界区最多只有一个线程能执行 |
| synchronized(同步锁) | 代码块在任意时刻最多只有一个线程能执行 |
线程安全
多线程并发同时对共享数据进行读写会造成混乱,也就是线程不安全。
示例如下:
package src.com.threadcase04;
import src.com.threadcase02.MyRun;
public class Demo {
public static void main(String[] args) throws Exception{
MyRun1 mr = new MyRun1();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("sum = "+Sum.sum);
}
}
class Sum {
public static int sum = 2000000;
}
package src.com.threadcase04;
public class MyRun1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
Sum.sum --;
//System.out.println(Sum.sum);
}
}
}

如上,有两个线程进行sum--,由于线程的并发性,使得线程1在操作的过程中,线程2抢了线程1进行了操作,导致两个线程同时对一个sum进行了减一。是的最终结果sum不为零;
当在线程里面加入System.out.println(Sum.sum)代码,运行结果就会是0,原因是println方法里面自带了synchronized锁。
上面这种情况就是线程不安全,在线程1运行时,线程2插入进来了,为了让线程安全,就要保证线程内部操作的原子性。
实现代码的原子性,就要对代码进行加锁解锁。
synchronized(lock){
Sum.sum ++;
}
修改如下
package src.com.threadcase04;
import src.com.threadcase02.MyRun;
public class Demo {
public static void main(String[] args) throws Exception{
MyRun1 mr = new MyRun1();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("sum = "+Sum.sum);
}
}
class Sum {
public static Object lock = new Object(); final只读,用于当作共享实例-锁
public static int sum = 2000000;
}
package src.com.threadcase04;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
public class MyRun1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (Sum.lock){
Sum.sum --;
}
// System.out.println(Sum.sum);
}
}
}
此时运行结果为0;
synchronized的用法:找出共享线程代码块,选择一个共享实例作为锁,使用synchronized(Lockobj){...};
Lockobj可以选择一个共享实例,例如定义一个 public static final Object lock = new Object(),使用synchronized(lock){...};;
本文讨论了多线程编程中如何确保线程安全,通过分析示例展示了不加锁的并发操作可能导致数据不一致,然后介绍了如何使用synchronized关键字实现代码的原子性和锁定机制,以保证在并发环境下的正确性。





