临界区:一段代码块内存在对共享资源的多线程读写操作,这段代码就是临界区。
竟态条件:多个线程在临界区执行,由于代码执行序列不同导致结果无法预测,称发生了竟态条件。
为了避免临界区的竟态条件发生,可以使用如下方案:
此次使用阻塞式解决方案:synchronized,俗称对象锁,这样,同一时刻只能有一个线程能持有对象锁,其他线程想获得这个对象锁就会被阻塞。
class test{h
public synchronized void test(){
}
}
//等价于
class test {
public void test() {
synchronized (this){
}
}
}
class test{
public synchronized static void test(){
}
}
//等价于
class test{
public static void test(){
synchronized (test.class){
}
}
}
以上等价写法很重要。
线程八锁就是考察synchronized锁住了哪些对象。
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
两个线程一起竞争锁,有可能是12,也有可能是21
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
两个线程一起竞争锁,所以可能是sleep1,然后2。或者2,或sleep1,然后1,2。
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
public void c() {
log.debug("3");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
new Thread(()->{ n1.c(); }).start();
}
c没加锁,a、b竞争,可能是sleep1,1、2,或者2,sleep1,1,3可以任意,但肯定在sleep之前。
所以可能是:
①3,sleep1、1,2
②3,2,sleep1,1
③2,3,sleep1,1
两个不同的对象,锁是不同的锁,所以没有竞争,一定是2,然后sleep1,1。
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
这就用到等价写法的知识了,可以看到这两个方法的锁对象不同,所以没有竞争关系,一定是2,然后sleep1,1。
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
两个锁的都是类对象,可能是sleep1,1,然后2,或者2,然后sleep1,1。
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
两个对象,一个是锁住类对象,一个锁住实例对象,所以没有竞争,总是2然后sleep1,1。
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
虽然对象不同,但是锁的都是类对象,所以有竞争。
可能是sleep1,1,然后2;或者2,然后sleep1,然后1。
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}