原子性 - 锁
原子性提供了互斥访问,同一时刻只能有一个线程对它进行操作。能保证同一时刻只有一个线程进行操作的,除了Atomic
包之外还有锁。主要有
-
synchronized
: 依赖JVM, 在这个关键字作用对象的作用范围内都是同一时刻只能由一个线程进行操作。 - Lock: 代码层面的锁, 依赖特殊的CPU指令, 代码实现,
ReentrantLock
原子性-synchronized
- 修饰代码块(被称为同步语句块):大括号括起来的代码,作用于调用的对象(调用这个代码块的对象)
- 修饰方法(被称为同步方法): 整个方法, 作用于调用的对象
- 修饰静态方法: 整个静态方法,作用于所有对象
- 修饰类: 括号括起来的部分, 作用于所有对象 synchronized.jpg
package io.haitaoc.concurrency.example.sync;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* synchronized示例
*/
public class SynchronizedExample1 {
public void test1(int j) {
// 修饰一个代码块, 作用于当前调用对象,不同对象间不影响
synchronized (this) { // 作用范围是 大括号括起来的部分, 作用对象是调用这部分代码的对象
for (int i = 0; i < 10; i++) {
System.out.println("test1 - " + i+" "+j);
}
} // 作用范围结束
}
// 修饰一个方法, 作用于当前调用对象,不同对象间不影响
public synchronized void test2(int j) { // 作用范围是整个方法, 作用调用此方法的对象
for (int i = 0; i < 10; i++) {
System.out.println("test2 - " + i+" "+j);
}
}
public static void main(String[] args) {
SynchronizedExample1 example1 = new SynchronizedExample1();
SynchronizedExample1 example2 = new SynchronizedExample1();
// 使用线程池, 相当于分别启动两个进程来执行test1()
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
example1.test2(1);
});
executorService.execute(()->{
example2.test2(2);
});
}
}
如果一个方法内部是一个完整的同步代码块,那么它和用
synchronized
修饰这个方法时等同的。注意:如果SynchronizedExample1
是父类,其子类在调用test1()
或test2()
时是不包含synchronized
的,原因在于synchronized
不属于方法声明的一部分,如果子类想要使用synchronized
,需要自己显示地在方法上进行声明
package io.haitaoc.concurrency.example.sync;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* synchronized示例
*/
public class SynchronizedExample2 {
public static void test1(int j) {
// 修饰一个类
synchronized (SynchronizedExample2.class) { // 作用范围是 大括号括起来的部分, 作用对象是调用这部分代码的对象
for (int i = 0; i < 10; i++) {
System.out.println("test1 - " + i+" "+j);
}
} // 作用范围结束
}
// 修饰一个静态方法, 作用于所有对象, 同一时刻只有一个线程可以执行
public static synchronized void test2(int j) { // 作用范围是整个方法, 作用调用此方法的对象
for (int i = 0; i < 10; i++) {
System.out.println("test2 - " + i+" "+j);
}
}
public static void main(String[] args) {
SynchronizedExample2 example1 = new SynchronizedExample2();
SynchronizedExample2 example2 = new SynchronizedExample2();
// 使用线程池, 相当于分别启动两个进程来执行test1()
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
example1.test1(1);
});
executorService.execute(()->{
example2.test1(2);
});
executorService.shutdown();
}
}
compare.jpg修饰类的整个代码块和修饰静态方法时的作用效果相同
网友评论