【北邮国院大三上】高级网络程序设计 Advance Network Programming——Block1

北邮国院大三电商在读,全文为PPT机翻+自己理解,仅做整体复习浏览知识点熟悉定义用,不做考前突击复习重点用。有任何问题可评论指出,有需要本文pdf/docx/md/Effiesheet格式的同学请私信联系/微信联系。祝您学习愉快。

process and thread

进程和线程

process

A process runs independently and isolated from other processes

进程独立运行,与其他进程隔离

A process cannot directly access shared data in other processes

进程不能直接访问其他进程的共享数据

The resources of the process, e.g., memory and CPU time, are allocated to it via the operating system

进程的资源,例如内存和CPU时间,是通过操作系统分配给它的

thread

A thread is a “lightweight process”

线程是一个“轻量级进程”

Each has its own call stack

每个都有自己的调用堆栈

Can access shared data of other threads in the same process

可以访问同一进程中其他线程的共享数据

Every thread has its own memory cache

每个线程都有自己的内存缓存

If a thread reads shared data, it stores this data in its own memory cache. A thread can re-read the shared data

如果线程读取共享数据,它将这些数据存储在自己的内存缓存中。线程可以重新读取共享数据

区别与联系(自行补充)

1.一个进程可以包含多个线程,线程在进程的内部。

2.进程之间的资源是独立的,线程之间的资源则是共享的。

每个进程都有独立的虚拟地址空间,也有之间独立的文件描述符表,同一进程的多个线程之间则共用这一份虚拟地址空间和文件描述符表。

3.进程是操作系统中资源分配的基本单位,线程是操作系统中调度执行的基本单位。

4.多个进程同时执行时,如果一个进程崩溃,一般不会影响其他进程,而同一进程内的多个线程之间,如果一个线程崩溃,很可能使得整个进程崩溃。

5.进程的上下文切换速度比较慢,而线程的上下文切换速度比较快。

6.进程的创建/销毁/调度开销大,线程的创建/销毁/调度开销相对少很多。

来源:https://blog.csdn.net/weixin_62988630/article/details/125915021

Atomicity

原子性

一个相当重要的概念,不止是在高编这一个科目。

An operation is said atomic when it cannot be interrupted

当一个操作不能被中断时,它被称为原子操作

【就是不能再分割成两个操作了】

  • Once it starts is always completes
  • One example assignment a = 5 (note: integer)

【这里有一个很经典的反例,a++ / a+=1 这种是没有atomic的,因为可以分割成两个操作】

Visibility

可见性

This occurs when a thread must watch the actions of another thread

当一个线程必须监视另一个线程的动作时,就会发生这种情况

  • e.g., for the termination of the thread; for a value being set

例如,用于线程的终止;对于正在设置的值

Order of execution :

When you have normal program, all you lines of code run in the same order every time. This is not the case with concurrent programming

当你有一个正常的程序时,所有的代码行每次都以相同的顺序运行。这不是并发编程的情况

The order of execution is not guaranteed!

执行的顺序没有保证!

【这句话相当重要,后面有一些东西就是在这句话的基础上的】

【简单解释一下:就是你有Thread 123,他执行的顺序可能是132,321,213等,不一定是123】

Critical code:

关键代码

A part of code that must only be executed by a single thread at one time

一次只能由单个线程执行的代码的一部分

  • e.g., writing to a file

Thread类

The Thread class is responsible for executing your stuff in a thread

Thread类负责在线程中执行你的东西

Your stuff is encapsulated in a run() method

您的内容封装在run()方法中

【就是说要重写run方法】

Two ways of giving the thread the run method:

  • Passing your class (with a run() method) into a new Thread object

将你的类(带有run()方法)传递给一个新的Thread对象

  • Extending the Thread class

扩展Thread类

创建Thread方法1:Runnable接口

  • 先implements Runnable

  • 再重载run()方法

  • 在main函数里,先new一个刚刚创建的类的对象,在new一个含有刚刚创建的对象参数的Thread对象

  • 调用start方法,开始调用run()

    public class Order implements Runnable{
    public void run(){}
    }
    public static void main(String[] args){
    Order order = new Order;
    Thread thread = new Thread(order);
    thread.start();
    }

code example

在一行内创建一个thread(也用的是Runnable)

Thread t = new Thread(new Runnable() 
{ public void run() { // stuff here } }); 

t.start();

创建Thread方法2:继承Thread对象

  • 先extends Thread

  • 再重载run()方法

  • 在main函数里创建一个这个类的对象

  • start()

    public class MyThread extends Thread{
    public void run(){}
    }
    public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start();
    }

两种方法的比较

一个类只能继承一个类,却可以有好多接口,所以更建议用implements Runnable

sleep()方法

sleep(long millis)

  • 参数的单位是milliseconds(毫秒)
  • 只能使current thread(当前线程)sleep

eg:Thread.sleep(1000)

  • 是静态方法(static),即可以sleep当前线程(Thread.sleep()),也可以sleep实例对象(t.sleep())[不推荐后者]
  • 只有sleep()和wait()会自动抛出InterruptedException

Yield

When a thread executes a thread yield, the executing thread is suspended and the CPU is given to some other runnable thread

当一个线程执行一个线程yield时,正在执行的线程被挂起,CPU被分配给其他可运行的线程

This thread will wait until the CPU becomes available again

该线程将等待直到CPU再次可用

Technically, in process scheduler’s terminology,

– the executing thread is returned to the ready queue of the processor and

– waits for its next turn

从技术上讲,在进程调度的术语中,

– 正在执行的线程被返回到处理器的就绪队列中

– 等待它的下一个回合

什么是interrupt

  • An interrupt is an indication to a thread that it should stop what it is doing and do something else

中断是对线程的一个指示,它应该停止正在做的事情并做其他事情

  • It does not stop the thread

【不会停止线程,他只是一个indication(指示),告诉线程"should"停止,至于停止与否interrupt决定不了】

  • 调用线程中的interrupt()方法来

Interrupt flag

  • 一个表示Thread是否被interrupt的Boolean变量
  • 默认为false(0)
  • 线程的运行并不会完全因为Interrupt flag的变化而停止,而是线程检测到Interrupt flag的变化后自行决定是否要停止进程

能检测/改变Interrupt flag的方法

t为我们要打断的进程

  • t.interrupt() —— 这里有两种情况

[non-static方法]

  1. 如果此时在sleeping或者waiting state(即sleep()和wait()方法被调用),那么interrupt()方法会打断sleeping/waiting state,将flag置为false,并且抛出InterruptedException

【三点:打断休眠,flag置0,抛出异常】

  1. 如果此时是正常状态,没有sleeping/waiting state,那么interrupt()方法只会把Interrupt flag置为true
  • t.interrupted()/Thread.interrupted

static方法,检验当前线程的interrupt flag是否为true,如果是true则将其改为false,返回true,如果是false则不变,返回false。

【静态方法说明既可以用Thread.interrupted(),也可以用t.interrupted()】

  • t.isInterrupted() 【注意I大写】

non-static方法,检验interrupt flag并返回其boolean值,不改变其boolean值!

【检验的时候用isInterrupted()!】

if(t.isInterrupted())==true //正确的
if(t.interrupted())==true //错误的,括号内永远是false

How to interrupt a thread 演示图

在这里插入图片描述

为什么要interrupt一个线程呢?

It is likely doing something that’s taking too long

它可能是在做一些花费太长时间的事情

– i.e., it is blocked

  • Blocking is when a thread is prevented from doing anything

阻塞是指线程被阻止做任何事情

  • What if we were waiting for a thread to complete, but it had gone to sleep?

如果我们正在等待线程完成,但它已经进入睡眠状态,会怎样?

– We might want to interrupt() it so we can continue

我们可能需要interrupt()它以便继续

Thread被blocked的原因

A thread may be blocked because:

– It has been put to sleep for a set amount of time

它已经休眠了一段时间

– The thread is suspended by call to wait(), and will become runnable on a notify or notifyAll message

线程通过调用wait()被挂起,并在notifynotifyAll消息上可运行

总结图

在这里插入图片描述

这个图很重要,标红的地方都要明白

join() 方法

  • 就是直到join()的线程结束了才继续主线程(pause了除了这个线程以外的所有线程)
  • This method is not static, so you can use it on any thread to wait for it to die

这个方法不是静态的,所以您可以在任何线程上使用它来等待它的死亡

  • Like sleep() this method throws InterruptedException when the thread is interrupted during waiting for an other thread

与sleep()类似,当线程在等待另一个线程时被中断时,此方法会抛出InterruptedException异常

举个例子解释一下:

	public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("test"));
        t.start();
        System.out.println("main1");
        try {
            t.join();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("main2");
    }

输出为main1 test main2 或 test main1 main2

main2一定在另外两个输出后面,说明是先进行了t线程,t结束后才继续主线程

isAlive() 方法

  • A thread is said to be alive when is has been started and is not dead yet

当一个线程已经启动并且还没有死的时候,它就被称为活线程

  • isAlive() method returns true if the thread upon which it is called is alive

如果调用它的线程是活的,isAlive()方法返回true

三种terminate(终止)线程的方法

  1. The thread has finished the work it is designed to do, and exits the run() method naturally

线程已经完成了它设计要做的工作,并自然退出run()方法

【即自然终止】

  • 不需要额外的行为,但可以利用shared Boolean变量来判断是否需要结束
  • share Boolean:比如写一个pleaseFinish变量,如果为true则终止
  • 但如果线程处于non-runnable state的话,则这个变量无用

non-runnable state

A thread is in a non-runnable state if

  • Its sleep method is invoked
  • The thread calls the wait method to wait for a specific condition to be satisfied
  • The thread is blocking on I/O

线程处于不可运行状态,如果

  • 调用它的sleep方法
  • 线程调用wait方法等待特定的条件被满足
  • 线程在I/O时阻塞
  1. The thread has been marked as daemon thread. When the parent thread who created this thread terminates, this thread will be forcefully terminated

该线程已被标记为守护线程。当创建此线程的父线程终止时,此线程将被强制终止

【即deamon thread的父线程终止时,子线程也终止】

deamon thread

  • myThread.setDeamon(true)
  • 将某个线程设置为守护线程,在所有线程结束后自动结束(即没有可以守护的线程,那么守护线程也就没用了)
  • setDeamon() before starting the thread
  1. The thread has received an interrupt signal, while doing its work

– It decides to not continue with work and exits the run() method

– It may also decide to ignore the signal and continue to work

线程在工作时收到了中断信号

– 它决定不继续工作并退出run()方法.

– 它也可能决定忽略信号,继续工作

【即interrupt】

Volatile

  • Volatile is used to indicate that a variable’svalue will bemodified by different threads

Volatile用于指示变量的值将被不同的线程修改

E.g., public volatile int counter = 0;

  • Access to the variable is only given to onethread at a time

对变量的访问一次只给一个线程

【即一个thread访问这个变量的时候,其他的thread不能访问】

The load, store, read, and write actionson volatile variables are atomic

volatile的一些易错点

  • If you declare arr[] as volatile, that means that the reference to the array is volatile; but individual field accesses (e.g., arr[5]) are not thread-safe

如果你将arr[]声明为volatile,这意味着对数组的引用是volatile的;但是单个字段访问(例如arr[5])是不线程安全的

  • Unary operations (

A danger of volatile variables is that they can misleadingly make a non-atomic operation look atomic.

volatile变量的一个危险是,它们会误导非原子操作看起来像原子操作。

For example:volatile int i; …i += 5;

NOT SAFE

  • Threads in Java cache variables

Java中的线程缓存变量

  • If a variable is modified, another thread’s cache may go out-of-date

如果一个变量被修改,另一个线程的缓存可能会过期

  • If you set a variable to volatile:

——The value of this variable will never be cached thread-locally

此变量的值永远不会被线程本地缓存

——All reads and writes will go straight to"main memory";

所有的读写都将直接进入“主存”

什么时候不用volatile

  • Volatile is not necessary for fields that declared final (i.e., will never change)

Volatile对于声明为final的字段(即永远不会改变)不是必需的。

  • Volatile is not necessary for variables that are accessed by only one thread

Volatile对于只被一个线程访问的变量不是必需的

  • Volatile is not suitable for complex operations

Volatile不适合复杂的操作

Even things like

  • x=x+5
  • Read x
  • Add 5 to x
  • Write x

Thread safe code

  • A piece of code is thread-safe if it only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time

如果一段代码仅以保证多个线程同时安全执行的方式操作共享数据结构,那么它就是线程安全的

  • Two threads should not manipulate the same variable at the same time without being protected against mistakes

两个线程不应该在同一时间操作同一个变量,否则会防止出错

举例

public class Example { 
    private int value = 0; 
    public int getNextValue(){ return value++; }
  • An increment like this is not a simple action, but three actions:
  1. Read the current value of “value”
  2. Add one to the current value
  3. Write that new value to “value”
  • Multiple threads may call getNextValue()
  • Volatile (on its own) does not help as value++ is not atomic++

Critical sections

  • The code segments within a program that access the same data from within separate, concurrent threads are known as critical sections

程序中从不同的并发线程中访问相同数据的代码段称为临界段

  • In the Java language, you mark critical sections (e.g., methods) in your program with the synchronized keyword

在Java语言中,您可以用synchronized关键字标记程序中的关键部分(例如,方法)

  • A synchronized section can only be accessed by a single thread at any give time

一个同步的部分在任何给定的时间内只能被单个线程访问

locks

  • We use locks to control/restrict access to critical sections

我们使用锁来控制/限制进入临界区

  • In Java, there are two types of locks:

– Intrinsic locks (the type locks we’ll talk about here) - every object can function as a lock that is triggered using the keyword synchronized

内在锁(我们将在这里讨论的类型锁)——每个对象都可以作为锁使用关键字synchronized触发

– Extrinsic locks (not covered)

外部锁(未涉及)

  • Intrinsic locks are also called monitors in Java

内在锁在Java中也称为监视器

  • A lock applies to a particular section of code

锁应用于代码的特定部分

  • If the code is locked, no other thread can execute it

如果代码被锁定,则没有其他线程可以执行它

  • If the code is unlocked, any thread can take the lock and execute it

如果代码被解锁,任何线程都可以获得锁并执行它

【很好理解,就是把线程锁住了,等解锁才能运行】

Intrinsic locks 内部锁

核心就是synchronized关键词的使用

  • 举例:

    public class MyThread extends Thread
    {
    public void hello(){}//无锁
    public void synchronized bye(){}//有锁
    }

  • When a thread has a lock, no other thread can acquire it

当一个线程拥有锁时,其他线程无法获得它

– It must wait for the first thread to release the lock

  • If you have two methods with the synchronized keyword,only one method of the two will be executed at the same time, because the same lock is used for all methods in an object

如果您有两个带有synchronized关键字的方法,那么这两个方法中只有一个方法会同时执行,因为同一个锁用于对象中的所有方法

  • 每一个object都有锁!

Explicit use of the intrinsic lock 内部锁的显式使用【synchronized的其他用法】

——synchronized statement!同步语句

protected synchronized int getNextAvailableItem() 
{… return items; } 

protected int getNextAvailableItem() 
{ synchronized (this){… return items; }}

//上下两个方法是一样的
  • Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock

与同步方法不同,同步语句必须指定提供内在锁的对象

  • Generally, critical sections in Java programs are methods

通常,Java程序中的临界区是方法

  • You can mark smaller code segments as synchronized

您可以将较小的代码段标记为同步的

  • For the majority of your Java programming purposes, it’s best to use synchronized only at the method level

对于大多数Java编程目的,最好只在方法级别使用同步

scope of a lock 锁的范围/作用域

  • The time between when the lock is taken and when the lock is released

取锁和释放锁之间的时间

– So far everything has been method scope

到目前为止,一切都是方法作用域

  • Lock scopes can be determined by segments of code

锁作用域可以由代码段确定

– E.g., a method or just a part of code

  • Remember, as always, locks apply to objects not methods

记住,和往常一样,锁应用于对象而不是方法

– A lock isn’t a method, it’s something that protects a method

锁不是方法,而是保护方法的东西

synchronized statement 的锁只覆盖了它后面框起来的语句, synchronized method的锁覆盖的是整个方法

Object as locks 作为锁的对象

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 

//这里直接把两个object当做锁来用,因为每一个对象都有锁

    public void inc1() 
        { synchronized(lock1) { c1++; } } 
    public void inc2()
        { synchronized(lock2) { c2++; } } 
}

Full synchronization 完全同步

  • A class in which every method is synchronised (that of course has no public instance variables) guarantees locally sequential behaviour

每个方法都同步的类(当然没有公共实例变量)保证了局部顺序行为

  • They only do one thing at a time. They are either:

– ready (idle - not having the lock), 准备好(空闲-没有锁),

– active (processing a method), or 工作中的(处理一个方法),或者

– waiting (for a reply) 等待(等待回复)

public class ExpandableArray{
    private Object[] data;
    private int size;
    public ExpandableArray(int cap){
        data=new Object[capacity];
        size=0;
    }
    public synchronized int size(){return size;}
    public synchronized Object at(int i) throws NoSuchElementException
    {return data[i];}
}

关于synchronization的其他问题

  • A synchronized method can call another nonsynchronized method. Only a synchronized method will be “locked”

同步方法可以调用另一个非同步方法。只有同步的方法才会被“锁定”

  • A synchronized method can call another synchronized method. Because it will already have the key, but only in the same object.There is one lock per object

同步方法可以调用另一个同步方法。因为它已经有了键,但只是在同一个对象中。每个对象有一个锁

  • Synchronization is implemented by exclusively accessing the underlying internal lock associated with an object, including the class object for static methods

同步是通过访问与对象(包括静态方法的类对象)关联的底层内部锁来实现的

  • Each lock acts as a counter

每个锁都充当计数器

– if counter is not 0 on entry to a synchronized method or block because another thread holds the lock, the current thread is blocked until the count is 0

如果在进入同步方法或块时计数器不为0,因为另一个线程持有锁,那么当前线程将被阻塞,直到计数器为0

– on entry the counter is incremented

在输入时,计数器递增

– on return or exit by an exception the counter is decremented

在通过异常返回或退出时,计数器递减

  • Any method or code block marked as synchronized is executed in its entirety

任何标记为同步的方法或代码块都将完整地执行

– Unless explicitly suspended by a wait

除非被等待显式挂起

– Other threads are blocked until the synchronized block can complete

其他线程被阻塞,直到同步块完成

  • If a method is not marked as synchronized then it can be executed immediately

如果一个方法没有被标记为同步,那么它可以立即执行

– Even when another method, even a synchronized method, of the object is executing

即使对象的另一个方法,甚至同步方法正在执行

【所有的lock只针对线程,而不针对其他的非同步的方法】

  • The synchronized qualifier is not automatically inherited

同步限定符不会自动继承

– you must qualify in the subclass when overriding else it is unsynchronized

当重写其他未同步的内容时,必须在子类中进行限定

  • A non-static method can lock static data using a code block
  • 非静态方法可以使用代码块锁定静态数据

– synchronized (getClass()) {…} is locking the class object and hence the static data

synchronized (getClass()){…}锁定了类对象,因此锁定了静态数据

【getClass() 返回此 Object 的运行时该对象的类. 该方法返回一个Class对象, 可以通过该对象可以获取某个类的相关信息, 如构造方法、属性、方法等。】

  • 只能synchronize对象!!!不能synchronize变量!!

    int i;
    synchronized(i){i=1;}//错误的,不能synchronize变量

Synchronized与volatile的对比

  • Only a primitive variable may be declared volatile

只有基元变量可以被声明为volatile

– E.g., an int

  • Access to a volatile variable never has the potential to block

对volatile变量的访问永远不会有阻塞的可能

– Volatile only protects atomic operations

Volatile只保护原子操作

– It is not suitable for complex operations, e.g., a = a +1

它不适合复杂的运算,例如a = a +1

  • A synchronized method can protect more complex code

monitor

【核心:cooperation

  • A lock that supports Cooperation through the wait() & notify() methods is called a Monitor

通过wait()和notify()方法支持合作的锁称为Monitor

– Enable threads to work together

使线程能够一起工作

  • Every Java object can serve as a monitor through the use of synchronized, wait(), notify()

通过使用synchronized、wait()、notify(),每个Java对象都可以充当监视器。

– Using synchronized creates the lock to protect the critical section of the code

使用synchronized创建锁来保护代码的关键部分(临界区)

– Calling wait() on an object pauses a thread and puts it in a wait set (the set of threads waiting for the lock to become free)

在对象上调用wait()暂停线程并将其放入等待集(等待锁释放的线程集)中。

– Calling notify() on that object re-awakens a thread from the wait set

在该对象上调用notify()将从等待集中重新唤醒一个线程

  • Allows threads to pause their execution and notify other threads of events

允许线程暂停其执行并通知其他线程事件

  • Java monitors are usually called “Wait and Notify monitors” or “Signal and Continue monitors”

Java监控器通常称为“等待和通知监控器”或“信号和继续监控器”

Enter set, Wait set, Owners

【核心是这张图】

在这里插入图片描述

【简要解释一下这个图:一个想上锁的线程,一开始要进入entry set排队(➀过程)。当entry set和wait set都没有在该线程前面的等待线程且没有人拥有锁的时候,进入The Owner区,获得锁(➁过程)。当这个线程完成执行后,释放并退出(➄过程)。当上锁的线程执行wait()的时候,会进入wait set(➂过程),当另一个线程执行notify()时,Wait Set中的线程会被唤醒,等待这个线程结束后,Wait Set中的线程会进入The Owner获得锁(➃过程)

  • ➀Threads entering a lock region are placed into an entry set for the associated monitor

进入锁区域的线程被放置到相关监视器的enter set中

  • ➁If no other thread is waiting in the entry set and no other thread currently owns the lock, the thread acquires the lock and continues executing the lock region

如果条目集中没有其他线程在等待,并且当前也没有其他线程拥有该锁,则该线程将获得该锁并继续执行锁区域

  • ➄When the thread finishes executing the lock region, it exits (and releases) the lock

当线程完成锁区域的执行时,它退出(并释放)锁

  • A thread that currently owns the lock can suspend itself inside the lock by executing a wait() command

当前拥有锁的线程可以通过执行wait()命令在锁中挂起自己

  • ➂When a thread executes a wait(), it releases the lock and enters a wait set

当线程执行wait()时,它会释放锁并进入等待集

– ➃The thread will stay suspended in the wait set until another thread executes a notify() command inside the lock

该线程将一直挂起在等待集中,直到另一个线程在锁中执行notify()命令

  • When a thread executes a notify, it continues to own the lock until it releases the lock of its own accord, either by executing a wait or by completing the lock region

当线程执行一个通知时,它将继续拥有锁,直到它通过执行等待或完成锁区域自行释放锁为止

  • ➃After the notifying thread has released the lock, the waiting thread will be resurrected and will reacquire the lock

在发出通知的线程释放锁后,等待的线程将被唤醒并重新获得锁

entry set 与 wait set的优先级与竞争问题

  • If the (former) lock owner did not execute a notify before it released the lock then only the threads in the entry set will compete to acquire the lock

如果(前一个)锁owner在释放锁之前没有执行notify,那么只有entry set的线程才会竞争获取锁

  • If the former owner did execute a notify, then the entry set threads will have to compete with one or more threads from the wait set

如果前一个owner确实执行了一个notify,那么entry set的线程将不得不与wait set的一个或多个线程竞争

【优先级:有notify则wait set与entry set竞争,无notify则只看entry set】

  • If a thread from the entry set wins the competition, it becomes the new owner of the lock

如果entry set中的线程赢得竞争,它将成为锁的新所有者

  • If a thread from the wait set wins the competition, it exits the wait set and reacquires the lock

如果来自wait set的线程赢得竞争,它将退出wait set并重新获得锁

  • A thread can only execute a wait command if it currently owns the lock

线程只能在当前拥有锁的情况下执行等待命令

– i.e., it is currently inside the synchronized block

也就是说,它当前在同步块中

notify() 与 notifyAll()

  • A notify() command selects one thread arbitrarily from the wait set and marks it for eventual resurrection

notify()命令从等待集中任意选择一个线程,并将其标记为最终的恢复

  • A notifyAll() command marks all threads currently in the wait set for eventual resurrection

notifyAll()命令标记当前等待集中的所有线程,以便最终恢复

【很简单,就是随便唤醒一个和唤醒所有的区别】

关于wait 和 notify的一些关键点

  • wait and notify should be placed within synchronized code to ensure that the current code owns the lock

等待和通知应该放在同步代码中,以确保当前代码拥有锁

【得先有锁才能说wait,notify】

  • you suspend yourself (sleep) with a wait when you cannot continue

当你不能继续时,你用wait来暂停自己(睡眠)

  • you let waiting threads know that data has changed by notify

通过notify让等待的线程知道数据已经更改

  • A call to wait from within synchronized code causes the thread to give up its lock and go to sleep (and adds it to the wait set)

从同步代码中调用wait会导致线程放弃锁并进入睡眠状态(并将其添加到wait set)

  • This normally happens to allow another thread to obtain the lock and continue some processing

这通常是为了允许另一个线程获得锁并继续一些处理

  • The wait method is meaningless without the use of notify or notifyAll which allows code that is waiting to be notified that it can wake up and continue executing

如果不使用notify或notifyAll,wait方法就没有意义,这两种方法允许等待notify的代码被唤醒并继续执行

Common usage pattern: wait condition

  • A condition is a logical statement that must hold true for the thread to proceed

条件是一个逻辑语句,必须为真,线程才能继续

  • If it is not true the thread must wait for the condition to become true

如果它不为真,线程必须等待条件变为真

比如:while( ! the condition which should be true) { wait(); }

Deadlock

  • Two or more threads waiting for two or more locks to be freed, and the circumstances in the program is such that the locks will never be freed

两个或多个线程等待释放两个或多个锁,而程序中的情况是锁永远不会被释放

  • The synchronization primitives let you create deadlock

同步原语允许您创建死锁

  • Java provides no mechanisms to support deadlock prevention

Java没有提供支持死锁预防的机制

图例:

在这里插入图片描述

Deadlock solution

  • Prevention

– Design code so deadlock is impossible

设计代码使死锁是不可能的

  • Avoidance

– Steer around deadlock with smart scheduling

通过明智的调度绕开死锁

  • Detection and Recovery

– Check for deadlock periodically

定期检查死锁

– Recover by killing threads and restarting

通过杀死线程并重新启动来恢复

Deadlock prevention

  • Avoid mutual exclusion (i.e., synchronized)

避免相互排斥(即同步)

  • Allow pre-emption

允许优先购买权

– i.e., allow a thread to interrupt another to take its lock

也就是说,允许一个线程中断另一个线程来获取它的锁

– Could be dangerous/suboptimal if thread hasn’t completed

如果线程没有完成,可能是危险的/次优的

  • Don’t allow a thread to hold multiple locks

不要允许一个线程持有多个锁

– Or force it to get all locks at the same time

或者强制它同时获得所有的锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值