原子性(Atomicity)
原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。如果一个操作时原子性的,那么多线程并发的情况下,就不会出现线程安全问题;
例如a++,对于共享变量a的操作,实际上会执行三个步骤,
1.读取变量a的值到寄存器
2.寄存器中的值+1
3.将值赋予变量a
这三个操作中任何一个操作过程中,a的值被人篡改,那么都会出现我们不希望出现的结果。所以必须保证这是原子性的。Java中的锁的机制解决了原子性的问题
Java 提供多种锁机制做线程同步, 保证只有一个线程能进入临界区:
-
Synchrnized 关键字:
使用方式:
- 指定加锁对象: 对给定Object 加锁, 进入同步代码前要取得该对象的锁;
- Object.wait():释放当前对象锁,当前线程 进入阻塞队列
- Object.notify():唤醒当前对象阻塞队列里的任一线程(并不保证唤醒哪一个)
- Object.notifyAll():唤醒当前对象阻塞队列里的所有线程
public class ThreadSyncObject{
final static Object object=new Object();
public static class T1 extends Thread{
public void run(){
synchronized (object){
System.out.println("T1 start!");
try{
System.out.println("T1 wait for object !");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1 end !");
}
}
}
public static class T2 extends Thread{
public void run(){
synchronized (object){
System.out.println("T2 start! notify one thread");
object.notifyAll();// 如果是object.notify()则只会通知一个T1线程,另外一个T1线程仍然在等待队列中,无法结束
System.out.println("T2 end !");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String args[]) throws InterruptedException {
Thread t1 = new T1();
Thread t1_1 = new T1();
t1.start();
t1_1.start();
Thread.sleep(1000);
Thread t2 = new T2();
t2.start();
t1.join();
t2.join();
}
}
- 如果使用object.notifyAll(), 两个T1线程都能正常从阻塞队列中恢复并结束:
T1 start! T1 wait for object ! T1 start! T1 wait for object ! T2 start! notify one thread T2 end ! T1 end ! T1 end ! Process finished with exit code 0
如果使用object.notify(), 始终会有一个T1线程一直在阻塞队列中,导致主进程无法结束:
T1 start! T1 wait for object ! T1 start! T1 wait for object ! T2 start! notify one thread T2 end ! T1 end !
- 对实例方法加锁: 给当前实例的方法加锁, 进入同步代码前要取得该对象的锁;
public class ThreadSyncFunc implements Runnable {
static int i=0;
public synchronized void add(){
i++;
}
@Override
public void run() {
for (int j=0; j<1000000; j++){
add();
}
}
public static void main(String args[]) throws InterruptedException {
ThreadSyncFunc mt = new ThreadSyncFunc();
Thread t1 = new Thread(mt, "t1");
Thread t2 = new Thread(mt, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
增加了同步操作的执行结果, 计算结果符合预期,等于2*1000000
:
2000000 Process finished with exit code 0
如果add() 函数去掉”synchronized
“,执行结果总是<2000000
1989320
Process finished with exit code 0
- 对static 方法加锁: 给当前类方法加锁,进入同步代码前要取得该对象的锁;
public class ThreadSyncStaticFunc implements Runnable {
static int i=0;
public static synchronized void add(){
i++;
}
@Override
public void run() {
for (int j=0; j<1000000; j++){
add();
}
}
public static void main(String args[]) throws InterruptedException {
ThreadSyncStaticFunc mt1 = new ThreadSyncStaticFunc();
ThreadSyncStaticFunc mt2 = new ThreadSyncStaticFunc();//因为是2个实例, 需要共同操作一个i类变量, 也需要把add()设置成类函数
Thread t1 = new Thread(mt1, "t1");
Thread t2 = new Thread(mt2, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
这个样例执行结果, 计算结果符合预期,等于2*1000000
:
2000000 Process finished with exit code 0
如果去掉synchronized 结果也总是<2000000
1501370
Process finished with exit code 0
没有评论