1.同步代码块,同步方法
同步代码块
-
代码块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句分装在方法体中,通过{}包围起来。
-
和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不通过对象或类显示调用,而是加载类时,或创建对象时隐形调用
public class MyThread extends Thread{static int ticket=0;static Lock lock=new ReentrantLock();@Overridepublic void run(){while(true){lock.lock();try {if(ticket==50){break;}else {Thread.sleep(100);ticket++;System.out.println(Thread.currentThread().getName()+" "+ticket);}} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();}}}
}
为什么要用同步代码块(好处)
优点:
1.相当于另一种形式的构造器(对构造器的补充机制),可以做初始化的操作。
应用场景:假设在类中多个构造器中有重复语句,可以抽取到初始化代码块中,提高代码的重用性。
2.和设计模式中的"单例设计模型"有关(与static修饰符关联有奇效)。
注意:代码块与构造器的调用规则:代码块的执行是优先于构造器的。
同步方法
public class MyRunnable implements Runnable{int ticket=0;public String name;@Overridepublic void run(){/*1.循环2.同步代码块(或者同步方法)3.判断共享数据是否到了末尾,如果到了末尾4.判断共享数据是否到了末尾,如果没到末尾*/while(true){synchronized (this){if (method()) break;}}}private boolean method() {if(ticket==50){return true;}else{try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}ticket++;System.out.println(Thread.currentThread().getName()+" "+ticket);}return false;}}
2.等待唤醒机制
等待唤醒机制中的方法
等待唤醒机制就是用于解决线程通信的问题的,使用到的3个方法的含义如下:
① wait方法:线程不再活动,不再参与调度,进入wait set中(一个等待的集合中),因此不会浪费CPU资源,也不会去竞争锁,这时的线程状态为WAITING(等待状态)。处于WAITING状态的线程需要等待别的线程的通知(notify),然后才能从wait set中释放出来,重新进入调度队列(ready queue)
② notify方法:通知在wait set中的一个线程释放,等待时间越久的约先释放
③ notifyAll方法:释放所有在wait set中的全部线程
注意:
哪怕只通知了一个处于等待中的线程,被通知的线程也不能立即回复执行,因为它是在判断了是否含有锁对象发现没有后才中断的,所以他需要再次尝试获取锁(这个过程很可能会面临其他线程的竞争),成功后才能在最开始调用wait方法之后的地方恢复执行
package com.lc.test02;import java.util.concurrent.TimeUnit;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitOne {/*** 注意:必须使用同一把锁*/static Object lock = new Object();public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {synchronized (lock) {System.out.println("进入" + Thread.currentThread().getName());try {lock.wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println(Thread.currentThread().getName() + "被唤醒");}}, "t1");t1.start();try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();}/*** 线程2*/Thread t2 = new Thread(() -> {synchronized (lock) {System.out.println("进入" + Thread.currentThread().getName());lock.notify();System.out.println("唤醒通知已发");}}, "t2");t2.start();}
}