Ожидание реализации механизма уведомления
Функция метода wait() состоит в том, чтобы заставить текущий поток ждать.Метод wait() является методом класса Object.Этот метод используется для помещения текущего потока в «очередь перед выполнением» и остановки выполнения в момент код, в котором находится wait(), пока не будет уведомлен или прерван. Метод wait() можно использовать только в методе синхронизации или в методе синхронизации.После выполнения wait() текущий поток снимает блокировку.
Метод notify() также вызывается в синхронизированном методе или в синхронизированном методе, и перед вызовом также должна быть получена блокировка объекта на уровне объекта. Этот метод используется для уведомления других потоков, которые могут ожидать блокировки объекта.Если есть несколько ожидающих потоков, планировщик потоков случайным образом выберет поток в состоянии ожидания и выдаст ему уведомление с уведомлением, чтобы он ожидает получения блокировки объекта.
После выполнения notify() текущий поток не снимает блокировку немедленно, блокировка будет снята только после того, как поток выйдет из блока синхронизированного кода, и поток в состоянии ожидания сможет получить блокировку. Когда первый поток ожидания, который получает блокировку объекта, завершает работу и освобождает блокировку, если объект снова не уведомлен, другие потоки в состоянии ожидания по-прежнему будут блокировать состояние ожидания до тех пор, пока объект не выдаст сообщение notify или notifyAll.
public class MyWait {
private final Object lock;
MyWait(Object lock){
this.lock=lock;
}
public void waitTest(){
try {
synchronized (lock){
System.out.println("开始 wait time = " + System.currentTimeMillis());
lock.wait();
System.out.println("结束 wait time = " + System.currentTimeMillis());
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public class MyNotify {
private final Object lock;
MyNotify(Object lock){
this.lock=lock;
}
public void notifyTest(){
synchronized (lock){
System.out.println("开始 notify time = " + System.currentTimeMillis());
lock.notify();
System.out.println("结束 notify time = " + System.currentTimeMillis());
}
}
}
public class Main {
public static void main(String[] args){
try {
Object lock = new Object();
MyWait myWait = new MyWait(lock);
new Thread(() -> myWait.waitTest()).start();
Thread.sleep(3000);
MyNotify myNotify = new MyNotify(lock);
new Thread(() -> myNotify.notifyTest()).start();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
开始 wait time = 1552812964325
开始 notify time = 1552812967328
结束 notify time = 1552812967328
结束 wait time = 1552812967328
Из вывода видно, что метод уведомления выполняется через 3 секунды, а метод после ожидания выполняется после выполнения метода уведомления.
Связанные методы
- wait() : заставить поток, вызывающий этот метод, снять блокировку общего ресурса, затем выйти из рабочего состояния и войти в очередь ожидания, пока он снова не проснется.
- wait(long): ждать в течение периода времени с течением времени, параметр time здесь миллисекунды, то есть ждать до n миллисекунд, если нет уведомления, оно истечет время ожидания и вернется.
- notify (): случайным образом разбудить «один поток», ожидающий того же общего ресурса в очереди ожидания, и заставить поток выйти из очереди ожидания и войти в состояние выполнения, то есть метод notify () уведомляет только «один поток» .
- notifyAll(): заставить все «все потоки», ожидающие одного и того же общего ресурса в очереди ожидания, выйти из очереди ожидания и перейти в состояние готовности к выполнению. В это время поток с наивысшим приоритетом выполняется первым, но он может выполняться случайным образом, в зависимости от реализации виртуальной машины JVM.
Основное состояние потока
-
новый (новый): создается новый объект потока.
-
работоспособный: после создания объекта потока другие потоки (например, основной поток) вызывают метод start() объекта. Потоки в этом состоянии находятся в пуле исполняемых потоков, ожидая, пока их выберет планировщик потоков, чтобы получить право на использование ЦП.
-
Бег: Поток в рабочем состоянии получает квант времени процессора и выполняет программный код.
-
блокировать: Состояние блокировки означает, что поток по какой-то причине отказывается от права на использование процессора, то есть отказывается от временного интервала процессора и временно прекращает работу. Пока поток не перейдет в рабочее состояние, нет возможности снова перевести квант времени процессора в рабочее состояние. Существует три типа блокировки:
(один).ждать блокировки: Текущий поток выполняет метод o.wait(), и JVM помещает поток в очередь ожидания.
(два).синхронная блокировка: Когда выполняющийся поток получает блокировку синхронизации объекта, если блокировка синхронизации занята другим потоком, JVM помещает поток в пул блокировок.
(三). **其他阻塞**: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- мертвых: поток run(), выполнение метода main() завершается или метод run() завершается из-за исключения, поток завершает свой жизненный цикл. Мертвые темы не могут быть восстановлены.
Код в этом разделеGitHub
Использование метода соединения
Во многих случаях основной поток создает и запускает подпотоки.Если в подпотоках выполняется большое количество трудоемких операций, основной поток часто сталкивается с завершением подпотоков. Если основной поток хочет дождаться завершения выполнения подпотока, используйте метод join() Функция join() состоит в том, чтобы дождаться уничтожения объекта потока.
В дополнение к методу join() класс Thread также предоставляет два метода с характеристиками тайм-аута: join(longmills) и join(longmills, int nanos). Эти два метода тайм-аута указывают, что если поток потока не завершится в течение указанного периода тайм-аута, он вернется из метода тайм-аута.
public class Main {
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName()+"正在执行");
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}, "线程1");
thread.start();
thread.join();
System.out.println("等待"+thread.getName()+"执行完");
}
}
// 输出
线程1正在执行
等待线程1执行完
Разница между джайн (лонг) и сном (лонг)
Функция метода join(long) реализована внутри метода wait(long), поэтому метод join(long) имеет характеристики снятия блокировки. Два спящих (долгих) не снимут блокировку.
Использование ThreadLocal
Совместное использование значений переменных может быть в форме общедоступных статических переменных.Все потоки используют одну и ту же общедоступную статическую переменную.Если вы хотите, чтобы каждый поток имел свою собственную общую переменную, вы можете использовать ThreadLocal для ее решения.
Связанные методы ThreadLocal:
- get(): возвращает значение в копии текущего потока этой локальной переменной потока.
- set(T value): устанавливает копию текущей локальной переменной потока в указанное значение.
- remove(): удаляет значение текущей локальной переменной потока.
- initialValue(): возвращает «начальное значение» текущего потока для этой локальной переменной потока.
Изоляция между переменными потока
public class ThreadLocalTeat {
public static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException{
int count = 30;
String name = "Thread-";
for (int i=0; i<count; i++){
Thread thread = new Thread(() -> {
threadLocal.set(Thread.currentThread().getName());
System.out.println(threadLocal.get());
}, name+i);
thread.start();
}
Thread.sleep(20000);
}
}
// 输出
Thread-0
Thread-4
Thread-3
Thread-6
Thread-2
Thread-1
Thread-7
。。。
Использование InheritableThreadLocal
Используйте класс InheritableThreadLocal, чтобы получить значение, унаследованное от родительского потока, в дочернем потоке.
public class InheritableThreadLocalTest extends InheritableThreadLocal {
@Override
protected Object childValue(Object parentValue) {
return super.childValue(parentValue);
}
@Override
protected Object initialValue() {
return System.currentTimeMillis();
}
}
* @date 2019/6/18 8:28
* @description
*/
public class InheritableTeat {
static public class Inner{
public static InheritableThreadLocalTest threadLocalTest = new InheritableThreadLocalTest();
}
public static void main(String[] args) throws InterruptedException{
for (int i = 0; i<3; i++){
System.out.println("在main线程中获取值:"+ Inner.threadLocalTest.get());
}
for (int i=0; i<3; i++){
new Thread(() -> {
System.out.println("在"+Thread.currentThread().getName()+"中获取值:"+ Inner.threadLocalTest.get());
}, "Thread-"+i).start();
}
Thread.sleep(1000);
}
}
// 输出
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在Thread-1中获取值:1560818029616
在Thread-2中获取值:1560818029616
在Thread-0中获取值:1560818029616
При использовании класса InheritableThreadLocal следует обратить внимание на то, что если основной поток изменяет значение в InheritableThreadLocal, в то время как дочерний поток получает значение, дочерний поток по-прежнему получает старое значение.
Добро пожаловать в публичный аккаунт: