Artikel ini membawa anda pengetahuan yang berkaitan tentang java, yang terutamanya memperkenalkan isu yang berkaitan dengan tiga elemen pengaturcaraan serentak, termasuk atomicity, keterlihatan, keteraturan dan generasinya Mari kita lihat sebab, definisi, dan lain-lain di bawah, saya harap ia akan membantu semua orang.
Pembelajaran yang disyorkan: "tutorial video java"
1 Atomicity
1.1 Definisi atomisiti
atomik merujuk kepada satu atau lebih operasi, yang sama ada dilaksanakan dan tidak terganggu oleh operasi lain semasa pelaksanaan. mereka semua. 1.2 Punca masalah atomicity
Pensuisan benang adalah punca masalah keatomisan adalah untuk meningkatkan penggunaan CPU.
Mengambil kira sebagai contoh, sekurang-kurangnya tiga arahan CPU diperlukan:
Arahan 1: Pertama, kiraan pembolehubah perlu dimuatkan dari memori ke daftar CPU; >- arahan 2: Selepas itu, lakukan 1 operasi dalam daftar;
- Arahan 3: Akhir sekali, tulis hasilnya ke memori (mekanisme cache menyebabkan cache CPU dan bukannya memori ditulis) .
- Kami menganggap count=0 Jika benang A menukar benang selepas arahan 1 dilaksanakan, dan benang A dan benang B laksanakan mengikut urutan dalam rajah di bawah, maka kami akan mendapati bahawa kedua-dua benang adalah. melaksanakan operasi Count =1, tetapi hasilnya bukanlah 2 yang kami jangkakan, tetapi 1.
1.3 Operasi atom
Dalam persekitaran berbilang benang, Java hanya menjamin bahawa pembolehubah dan operasi penugasan jenis data asas adalah atom (
Nota : Dalam persekitaran JDK 32-bit, membaca data 64-bit bukan operasi atom*, seperti long, double
)1.4 Bagaimana untuk menyelesaikan masalah atomicity
Jika kita boleh memastikan bahawa pengubahsuaian kepada pembolehubah yang dikongsi adalah saling eksklusif, maka atomicity boleh dijamin sama ada CPU teras tunggal atau CPU berbilang teras. Mengunci boleh menyelesaikan masalah atomicity, seperti menggunakan disegerakkan dan kunci.
2 Keterlihatan
2.1 Definisi keterlihatan
Keterlihatan merujuk kepada apabila berbilang rangkaian mengendalikan pembolehubah dikongsi, di mana Selepas satu utas mengubah suai pembolehubah, utas lain boleh melihat hasil pengubahsuaian dengan serta-merta.
2.2 Punca Masalah Keterlihatan
Ketekalan data antara cache CPU dan memori adalah punca masalah keterlihatan CPU adalah untuk meningkatkan kecekapan CPU.
2.3 Penyelesaian Masalah Keterlihatan
Punca masalah keterlihatan ialah cache CPU, maka kita boleh melumpuhkan cache CPU.
Medan yang tidak menentu boleh melumpuhkan cache CPU dan menyelesaikan isu keterlihatan.
- Kedua-dua disegerakkan dan kunci boleh menjamin keterlihatan.
- 2.4 Apakah peraturan keterlihatan
Peraturan keterlihatan ialah peraturan Berlaku-Sebelum.
Berlaku-Sebelum peraturan:
Ringkasnya:
- Hasil operasi sebelumnya dapat dilihat oleh operasi berikutnya . Berlaku-Sebelum mengekang tingkah laku pengoptimuman pengkompil Walaupun pengkompil dibenarkan untuk mengoptimumkan, ia memerlukan pengkompil untuk mematuhi peraturan Happens-Before selepas pengoptimuman.
- 2.5 Berlaku-Sebelum peraturan
Peraturan jujukan program Dalam urutan, ikuti atur cara , operasi sebelumnya berlaku-sebelum sebarang operasi berikutnya.
① Berlaku-Sebelum ② .
class Example {
public void test() {
int x = 42; ①
int y = 20; ②
}
}
peraturan pembolehubah meruap Operasi tulis kepada pembolehubah meruap akan berlaku-sebelum operasi baca seterusnya kepada pembolehubah meruap.
Peraturan Transitif Jika A Berlaku-Sebelum B, dan B Berlaku-Sebelum C, maka A Berlaku-Sebelum C.
class Example {
int x = 0;
volatile int y = 0;
public void writer() {
x = 42; ①
y = 1; ②
}
public void reader() {
if (y == 1) { ③
// 这里x会是多少呢?
}
}
}
① Berlaku-Sebelum ②, peraturan yang memuaskan 1-peraturan berjujukan.
- ② Berlaku-Sebelum ③, peraturan yang memuaskan 2-peraturan pembolehubah tidak menentu.
- ① Berlaku-Sebelum ③, peraturan 3-peraturan transitif yang memuaskan. Jika y == 1, maka x = 42;
-
Peraturan untuk kunci dalam monitor Membuka kunci Berlaku-Sebelum untuk mengunci kunci ini seterusnya.
管程是一种通用的同步原语,在 Java 中指的就是 synchronized,synchronized 是 Java 里对管程的实现。
synchronized (this) { //此处自动加锁
// x是共享变量,初始值=10
if (this.x < 12) {
this.x = 12;
}
} //此处自动解锁
假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁);
线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12。
它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。
3 有序性
3.1 有序性的定义
有序性,即程序的执行顺序按照代码的先后顺序来执行。
3.2 有序性问题原因
编译器为了优化性能,有时候会改变程序中语句的先后顺序。
例如:“a=6;b=7;”编译器优化后可能变成“b=7;a=6;”,在这个例子中,编译器调整了语句的顺序,但是不影响程序的最终结果。
以双重检查代码为例:
public class Singleton {
static Singleton instance;
static Singleton getInstance(){
if (instance == null) { ①
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton(); ②
}
}
return instance;
}
}
上面的代码有问题,问题在 ② 操作上:经过优化后的执行路径是这样的:
- 分配一块内存 M;
- 将 M 的地址赋值给 instance 变量;
- 最后在内存 M 上初始化 Singleton 对象。
优化后会导致什么问题呢?我们假设线程 A 先执行 getInstance() 方法,当执行完 ① 时恰好发生了线程切换,切换到了线程 B 上;如果此时线程 B 也执行 getInstance() 方法,那么线程 B 在执行第一个判断时会发现 instance != null ,所以直接返回 instance,而此时的 instance 是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。
如何解决双重检查问题?变量用 volatile 来修饰,禁止指令重排序。
public class Singleton {
static volatile Singleton instance;
static Singleton getInstance(){
if (instance == null) { ①
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton(); ②
}
}
return instance;
}
}
推荐学习:《java视频教程》
Atas ialah kandungan terperinci Ketahui lebih lanjut mengenai tiga elemen pengaturcaraan serentak Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!