mysql 死锁监视器_并发基础知识:死锁和对象监视器

mysql 死锁监视器

本文是我们名为Java Concurrency Essentials的学院课程的一部分。

在本课程中,您将深入探讨并发的魔力。 将向您介绍并发和并发代码的基础知识,并学习诸如原子性,同步和线程安全性的概念。 在这里查看 !

目录

1.活泼
1.1。 僵局 1.2。 饥饿
2.使用wait()和notify()进行对象监控
2.1。 带wait()和notify()的嵌套同步块 2.2。 同步块中的条件
3.多线程设计
3.1。 不变的对象 3.2。 API设计 3.3。 线程本地存储

1.活泼

在开发使用并发实现目标的应用程序时,您可能会遇到不同线程可能相互阻塞的情况。 由于整个应用程序的运行速度比预期的慢,因此我们可以说应用程序无法按预期的时间完成。 在本节中,我们将仔细研究可能危害多线程应用程序正常运行的问题。

僵局

术语“死锁”对于软件开发人员来说是众所周知的,即使是大多数普通计算机用户也经常会使用“死锁”这个术语,尽管它并非总是以正确的含义使用。 严格说来,这意味着两个(或更多)线程分别在另一个线程上等待以释放其已锁定的资源,而线程本身已锁定另一个线程在等待的资源:

Thread 1: locks resource A, waits for resource BThread 2: locks resource B, waits for resource A

为了更好地理解该问题,让我们看一下以下源代码:

public class Deadlock implements Runnable {private static final Object resource1 = new Object();private static final Object resource2 = new Object();private final Random random = new Random(System.currentTimeMillis());public static void main(String[] args) {Thread myThread1 = new Thread(new Deadlock(), "thread-1");Thread myThread2 = new Thread(new Deadlock(), "thread-2");myThread1.start();myThread2.start();}public void run() {for (int i = 0; i < 10000; i++) {boolean b = random.nextBoolean();if (b) {System.out.println("[" + Thread.currentThread().getName() + "] Trying to lock resource 1.");synchronized (resource1) {System.out.println("[" + Thread.currentThread().getName() + "] Locked resource 1.");System.out.println("[" + Thread.currentThread().getName() + "] Trying to lock resource 2.");synchronized (resource2) {System.out.println("[" + Thread.currentThread().getName() + "] Locked resource 2.");}}} else {System.out.println("[" + Thread.currentThread().getName() + "] Trying to lock resource 2.");synchronized (resource2) {System.out.println("[" + Thread.currentThread().getName() + "] Locked resource 2.");System.out.println("[" + Thread.currentThread().getName() + "] Trying to lock resource 1.");synchronized (resource1) {System.out.println("[" + Thread.currentThread().getName() + "] Locked resource 1.");}}}}}
}

从上面的代码可以看出,启动了两个线程并尝试锁定两个静态资源。 但是对于死锁,两个线程需要不同的顺序,因此我们利用Random实例选择线程首先要锁定的资源。 如果布尔变量b为true,则首先锁定resource1,然后线程尝试获取对资源2的锁定。如果b为false,则线程首先锁定resource2,然后尝试锁定resource1。 在我们到达第一个死锁之前,该程序不必运行很长时间,即,如果我们不终止它,该程序将永远挂起:

[thread-1] Trying to lock resource 1.[thread-1] Locked resource 1.[thread-1] Trying to lock resource 2.[thread-1] Locked resource 2.[thread-2] Trying to lock resource 1.[thread-2] Locked resource 1.[thread-1] Trying to lock resource 2.[thread-1] Locked resource 2.[thread-2] Trying to lock resource 2.[thread-1] Trying to lock resource 1.

在此执行中,线程1持有资源2的锁,并等待对resource1的锁,而线程2持有资源1的锁,并等待resource2。

如果将上面示例代码中的布尔变量b设置为true,则不会遇到任何死锁,因为线程1和线程2请求锁的顺序始终相同。 因此,两个线程中的一个首先获取锁,然后请求第二个锁,因为其他线程都在等待第一个锁,所以第二个锁仍然可用。

通常,可以确定以下死锁要求:

  • 互斥:有一种资源在任何时间点只能由一个线程访问。
  • 资源持有:锁定一个资源后,线程尝试获取某个其他排他资源上的另一个锁定。
  • 无抢占:没有机制,如果一个线程在特定时间段内持有锁,则该机制可以释放资源。
  • 循环等待:在运行时发生一个星座,其中两个(或更多)线程分别在另一个线程上等待以释放已锁定的资源。

尽管要求清单看起来很长,但更高级的多线程应用程序存在死锁问题并不罕见。 但是,如果您能够放宽上述要求之一,则可以尝试避免死锁:

  • 互斥:这是一项通常不能放宽的要求,因为必须专门使用资源。 但这并非总是如此。 使用DBMS系统时,可以使用一种称为Optimistic Locking的技术,而不是在必须更新的某些表行上使用悲观锁,这是一种可能的解决方案。
  • 在等待另一个排他资源时避免资源持有的可能解决方案是在算法开始时锁定所有必要的资源,并在不可能获得所有锁定的情况下释放所有资源。 当然,这并非总是可能的,锁定的资源可能并不事先知道,或者就像浪费资源一样。
  • 如果无法立即获得锁定,则避免超时的可能解决方案是引入超时。 例如,SDK类ReentrantLock提供了指定锁定超时的可能性。
  • 从上面的示例代码可以看出,如果不同线程之间的锁定请求顺序没有不同,则不会出现死锁。 如果您能够将所有锁定代码放入所有线程都必须通过的一种方法中,则可以轻松地控制它。

在更高级的应用程序中,您甚至可以考虑实现死锁检测系统。 在这里,您将必须实现某种类型的线程监视,其中每个线程都报告已成功获取锁以及其尝试获取锁的尝试。 如果将线程和锁建模为有向图,则可以检测到两个不同的线程何时拥有资源,同时请求另一个阻塞的资源。 然后,如果您可以强制阻塞线程释放获得的资源,则可以自动解决死锁情况。

饥饿

调度程序决定下一步应该在状态RUNNABLE中执行的线程 。 该决定基于线程的优先级; 因此,具有较低优先级的线程比具有较高优先级的线程获得的CPU时间更少。 听起来很合理的功能在滥用时也会引起问题。 如果大多数时间都执行高优先级的线程,则低优先级的线程似乎“饿死了”,因为它们没有足够的时间正确执行其工作。 因此,建议仅在有充分理由的情况下设置线程的优先级。

线程匮乏的一个复杂示例是例如finalize()方法。 Java语言的此功能可用于在对象被垃圾回收之前执行代码。 但是,当您查看终结器线程的优先级时,您可能会发现它的运行优先级最高。 因此,如果与其他代码相比,对象的finalize()方法花费太多时间,则可能导致线程不足。

执行时间的另一个问题是问题,即未定义线程传递同步块的顺序。 当许多并行线程必须传递某些封装在同步块中的代码时,某些线程可能要比其他线程等待更长的时间,直到它们可以进入该块为止。 从理论上讲,它们可能永远不会进入障碍。

后一种问题的解决方案是所谓的“公平”锁定。 当选择下一个要传递的线程时,公平锁会考虑线程的等待时间。 Java SDK提供了一个公平锁的示例实现:java.util.concurrent.locks.ReentrantLock。 如果使用布尔标志设置为true的构造函数,则ReentrantLock授予对最长等待线程的访问权限。 这保证了没有饥饿,但是同时引入了以下问题:没有考虑线程优先级,因此可能会更频繁地执行经常在此屏障处等待的优先级较低的线程。 最后但并非最不重要的一点是,ReentrantLock类当然只能考虑正在等待锁的线程,即,执行频率足以达到锁的线程。 如果线程优先级太低,则可能不会经常发生这种情况,因此,具有更高优先级的线程仍会更频繁地通过锁。

2.使用wait()和notify()进行对象监控

多线程计算中的一个常见任务是让一些工作线程正在等待其生产者为其创建工作。 但是,据我们了解,就CPU时间而言,在循环中忙于等待并检查某些值并不是一个好的选择。 在此用例中,Thread.sleep()方法也没有太大价值,因为我们希望在提交后立即开始工作。

因此,Java编程语言具有另一种可在这种情况下使用的构造:wait()和notify()。 每个对象都从java.lang.Object类继承的wait()方法可用于暂停当前线程执行,并等待直到另一个线程使用notify()方法将我们唤醒。 为了正常工作,调用wait()方法的线程必须持有它已获得的锁,然后才能使用synced关键字。 当调用wait()时,锁被释放,线程等待直到拥有该锁的另一个线程在同一对象实例上调用notify()。

在多线程应用程序中,当然可能有多个线程在等待某个对象的通知。 因此,有两种不同的唤醒线程的方法:notify()和notifyAll()。 第一种方法仅唤醒其中一个等待线程,而notifyAll()方法将其全部唤醒。 但是请注意,与synced关键字类似,没有规则指定在调用notify()时接下来唤醒哪个线程。 在简单的生产者和消费者示例中,这无关紧要,因为我们对哪个线程完全唤醒的事实不感兴趣。

下面的代码演示了如何使用wait()和notify()机制来使使用者线程等待从某个生产者线程推送到队列中的新工作:

package a2;import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;public class ConsumerProducer {private static final Queue queue = new ConcurrentLinkedQueue();private static final long startMillis = System.currentTimeMillis();public static class Consumer implements Runnable {public void run() {while (System.currentTimeMillis() < (startMillis + 10000)) {synchronized (queue) {try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}if (!queue.isEmpty()) {Integer integer = queue.poll();System.out.println("[" + Thread.currentThread().getName() + "]: " + integer);}}}}public static class Producer implements Runnable {public void run() {int i = 0;while (System.currentTimeMillis() < (startMillis + 10000)) {queue.add(i++);synchronized (queue) {queue.notify();}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}synchronized (queue) {queue.notifyAll();}}}public static void main(String[] args) throws InterruptedException {Thread[] consumerThreads = new Thread[5];for (int i = 0; i < consumerThreads.length; i++) {consumerThreads[i] = new Thread(new Consumer(), "consumer-" + i);consumerThreads[i].start();}Thread producerThread = new Thread(new Producer(), "producer");producerThread.start();for (int i = 0; i < consumerThreads.length; i++) {consumerThreads[i].join();}producerThread.join();}
}

main()方法启动五个使用者线程和一个生产者线程,然后等待它们完成。 然后,生产者线程将新值插入队列,然后通知所有等待线程发生了某些事情。 使用者线程获取队列锁,然后进入睡眠状态,以便稍后再次填充队列时被唤醒。 生产者线程完成工作后,会通知所有消费者线程唤醒。 如果我们不做最后一步,那么消费者线程将永远等待下一个通知,因为我们没有为等待指定任何超时。 取而代之的是,我们至少可以在经过一定时间后使用wait(long timeout)方法来唤醒它。

带wait()和notify()的嵌套同步块

如上一节所述,在对象监视器上调用wait()仅释放该对象监视器上的锁。 由同一线程持有的其他锁不会被释放。 因为这很容易理解,所以在日常工作中,调用wait()的线程可能会进一步锁定。 而且,如果其他线程也在等待这些锁,则会发生死锁情况。 让我们看下面的示例代码:

public class SynchronizedAndWait {private static final Queue queue = new ConcurrentLinkedQueue();public synchronized Integer getNextInt() {Integer retVal = null;while (retVal == null) {synchronized (queue) {try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}retVal = queue.poll();}}return retVal;}public synchronized void putInt(Integer value) {synchronized (queue) {queue.add(value);queue.notify();}}public static void main(String[] args) throws InterruptedException {final SynchronizedAndWait queue = new SynchronizedAndWait();Thread thread1 = new Thread(new Runnable() {public void run() {for (int i = 0; i < 10; i++) {queue.putInt(i);}}});Thread thread2 = new Thread(new Runnable() {public void run() {for (int i = 0; i < 10; i++) {Integer nextInt = queue.getNextInt();System.out.println("Next int: " + nextInt);}}});thread1.start();thread2.start();thread1.join();thread2.join();}
}

正如我们之前所了解的 ,将同步添加到方法签名等于创建一个synced(this){}块。 在上面的示例中,我们意外地向该方法添加了synced关键字,然后在对象监视器队列上进行了同步,以便在等待队列中的下一个值时将当前线程置于睡眠状态。 然后,当前线程释放队列上的锁保持,但不释放对此的锁保持。 putInt()方法通知睡眠线程已添加新值。 但是,偶然地,我们还向该方法添加了关键字sync。 现在,当第二个线程进入睡眠状态时,它仍然持有该锁。 然后,第一个线程无法进入方法putInt(),因为此锁由第一个线程持有。 因此,我们陷入僵局,程序挂起。 如果执行上面的代码,则在程序开始后立即发生。

在日常生活中,情况可能不像上面那样清楚。 线程持有的锁可能取决于运行时参数和条件,而导致问题的同步块可能与代码中我们放置wait()调用的位置不太接近。 这使得很难找到此类问题,并且可能是这些问题仅在一段时间后或在高负载下才会出现。

同步块中的条件

在对同步对象执行某些操作之前,通常您必须检查是否满足某些条件。 例如,当您有一个队列时,您要等待直到该队列被填满。 因此,您可以编写一种检查队列是否已满的方法。 如果没有,则在唤醒当前线程之前使其处于睡眠状态:

public Integer getNextInt() {Integer retVal = null;synchronized (queue) {try {while (queue.isEmpty()) {queue.wait();}} catch (InterruptedException e) {e.printStackTrace();}}synchronized (queue) {retVal = queue.poll();if (retVal == null) {System.err.println("retVal is null");throw new IllegalStateException();}}return retVal;
}

上面的代码在调用wait()之前在队列上进行同步,然后在while循环内等待,直到队列中至少有一个条目。 第二个同步块再次将队列用作对象监视器。 它轮询()队列中的内部值。 为了演示起见,当poll()返回null时,抛出IllegalStateException。 当队列中没有要轮询的值时,就是这种情况。

运行此示例时,您将看到IllegalStateException很快就会抛出。 尽管我们已经在队列监视器上正确地同步了,但是会抛出异常。 原因是我们有两个单独的同步块。 假设我们有两个线程到达了第一个同步块。 第一个线程进入该块并由于队列为空而进入睡眠状态。 第二个线程也是如此。 现在,当两个线程都唤醒时(通过另一个在监视器上调用notifyAll()的线程),它们都在队列中看到了一个值(生产者添加的值。然后,两个线程到达第二个屏障。轮询队列中的值,当第二个线程进入时,队列已为空,因此它从poll()调用返回的值作为null并引发异常。

为避免出现上述情况,您将必须在同一同步块中执行所有取决于监视器状态的操作:

public Integer getNextInt() {Integer retVal = null;synchronized (queue) {try {while (queue.isEmpty()) {queue.wait();}} catch (InterruptedException e) {e.printStackTrace();}retVal = queue.poll();}return retVal;
}

在这里,我们在与isEmpty()方法相同的同步块中执行方法poll()。 通过同步块,我们可以确保在给定的时间点上只有一个线程正在此监视器上执行方法。 因此,没有其他线程可以从isEmpty()和poll()调用之间的队列中删除元素。

3.多线程设计

正如我们在上一节中所看到的,实现多线程应用程序有时比乍一看要复杂。 因此,在启动项目时务必牢记清晰的设计。

不变的对象

在这种情况下,非常重要的一种设计规则是不变性。 如果在不同线程之间共享对象实例,则必须注意两个线程不会同时修改同一对象。 但是在无法更改的情况下,不可修改的对象很容易处理。 要修改数据时,始终必须构造一个新实例。 基本类java.lang.String是不可变类的示例。 每次您要更改字符串时,都会得到一个新实例:

String str = "abc";String substr = str.substring(1);

尽管创建对象的操作并非没有成本,但是这些成本经常被高估。 但是,如果具有不可变对象的简单设计胜过不使用不可变对象,则总要权衡一下,因为存在存在并发错误的风险,而该错误可能会在项目后期出现。

在下面的内容中,您将找到一组要使类不可变的规则:

  • 所有字段均应为最终字段和私有字段。
  • 不应使用setter方法。
  • 为了防止子类违反不变性原则,应将类本身声明为final。
  • 如果字段不是原始类型,而是对另一个对象的引用:
    • 不应有将引用直接暴露给调用方的getter方法。

下列类的实例表示一条消息,其中包含主题,消息正文和一些键/值对:

public final class ImmutableMessage {private final String subject;private final String message;private final Map<String,String> header;public ImmutableMessage(Map<String,String> header, String subject, String message) {this.header = new HashMap<String,String>(header);this.subject = subject;this.message = message;}public String getSubject() {return subject;}public String getMessage() {return message;}public String getHeader(String key) {return this.header.get(key);}public Map<String,String> getHeaders() {return Collections.unmodifiableMap(this.header);}
}

该类是不可变的,因为它的所有字段都是final和private。 在构造实例之后,没有任何方法可以修改实例的状态。 返回对主题和消息的引用是安全的,因为String本身是一个不变的类。 例如,获得消息引用的呼叫者无法直接对其进行修改。 对于标题映射,我们必须更加注意。 只要返回对Map的引用,调用者就可以更改其内容。 因此,我们必须返回通过调用Collections.unmodifiableMap()获得的不可修改的Map。 这将返回Map上的一个视图,该视图允许调用者读取值(再次为字符串),但不允许修改。 尝试修改Map实例时,将引发UnsupportedOperationException。 在此示例中,返回特定键的值也是安全的,就像在getHeader(String key)中完成操作一样,因为返回的String再次是不可变的。 如果Map包含本身不可变的对象,则此操作将不是线程安全的。

API设计

在设计类的公共方法(即此类的API)时,您也可以尝试将其设计用于多线程使用。 当对象处于特定状态时,您可能有不应执行的方法。 克服这种情况的一种简单解决方案是拥有一个私有标志,该标志指示我们处于哪种状态,并在不应该调用特定方法的情况下抛出例如IllegalStateException:

public class Job {private boolean running = false;private final String filename;public Job(String filename) {this.filename = filename;}public synchronized void start() {if(running) {throw new IllegalStateException("...");}...}public synchronized List getResults() {if(!running) {throw new IllegalStateException("...");}...}
}

上面的模式通常也被称为“禁止模式”,因为该方法一旦在错误的状态下执行便会失败。 但是您可以使用静态工厂方法设计相同的功能,而无需在每个方法中检查对象的状态:

public class Job {private final String filename;private Job(String filename) {this.filename = filename;}public static Job createAndStart(String filename) {Job job = new Job(filename);job.start();return job;}private void start() {...}public synchronized List getResults() {...}
}

静态工厂方法使用私有构造函数创建Job的新实例,并已在实例上调用start()。 返回的Job引用已经处于可以使用的正确状态,因此getResults()方法仅需要同步,而不必检查对象的状态。

线程本地存储

到目前为止,我们已经看到线程共享相同的内存。 就性能而言,这是在线程之间共享数据的好方法。 如果我们将使用单独的进程来并行执行代码,那么我们将拥有更繁重的数据交换方法,例如远程过程调用或文件系统或网络级别的同步。 但是,如果同步不正确,则在不同线程之间共享内存也将难以处理。

Java中通过java.lang.ThreadLocal类提供了仅由我们自己的线程而不是其他线程使用的专用内存:

private static final ThreadLocal myThreadLocalInteger = new ThreadLocal();

通用模板参数T给出了应存储在ThreadLocal中的数据类型。在上面的示例中,我们仅使用了Integer,但在这里我们也可以使用任何其他数据类型。 以下代码演示了ThreadLocal的用法:

public class ThreadLocalExample implements Runnable {private static final ThreadLocal threadLocal = new ThreadLocal();private final int value;public ThreadLocalExample(int value) {this.value = value;}@Overridepublic void run() {threadLocal.set(value);Integer integer = threadLocal.get();System.out.println("[" + Thread.currentThread().getName() + "]: " + integer);}public static void main(String[] args) throws InterruptedException {Thread threads[] = new Thread[5];for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(new ThreadLocalExample(i), "thread-" + i);threads[i].start();}for (int i = 0; i < threads.length; i++) {threads[i].join();}}
}

您可能想知道,尽管变量threadLocal被声明为静态的,但每个线程输出的正是它通过构造函数获得的值。 ThreadLocal的内部实现确保每次调用set()时,给定值都存储在仅当前线程有权访问的内存区域中。 因此,当您事后调用get()时,尽管存在其他线程可能已调用set()的事实,但您仍会检索之前设置的值。

Java EE世界中的应用程序服务器大量使用ThreadLocal功能,因为您有许多并行线程,但是每个线程都有自己的事务或安全上下文。 由于您不想在每次方法调用中传递这些对象,因此只需将其存储在线程自己的内存中,并在以后需要时访问它。

翻译自: https://www.javacodegeeks.com/2015/09/concurrency-fundamentals-deadlocks-and-object-monitors.html

mysql 死锁监视器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python ks值计算_利用Python计算KS的实例详解

在金融领域中&#xff0c;我们的y值和预测得到的违约概率刚好是两个分布未知的两个分布。好的信用风控模型一般从准确性、稳定性和可解释性来评估模型。sOf免费资源网一般来说。好人样本的分布同坏人样本的分布应该是有很大不同的&#xff0c;KS正好是有效性指标中的区分能力指…

教你如何用一句话激怒IT人

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删在IT行业摸爬滚打这么久&#xff0c;你是否听过下面这些话&#xff1a;“这个很简单&#xff0c;我也是做程序出身的。”“预算砍掉一半&#xf…

java的网络编程有用吗_十大有用但又偏执的Java编程技术

java的网络编程有用吗经过一段时间的编码&#xff08;以我为例&#xff0c;大约20年左右&#xff0c;当您玩得开心时光飞逝&#xff09;&#xff0c;人们开始接受这些习惯。 因为&#xff0c;你知道... 任何可能出错的事情都会发生。 这就是为什么人们会采用“防御性编程”的原…

python bootstrap 4_Python3.4+Django1.9+Bootstrap3

实现和原理Python集成Django开发框架后&#xff0c;可以通过在cmd命令提示符下建立工程&#xff0c;工程名为learn_modelsdjango-admin.py startproject learn_models再进入到learn_models里面&#xff0c;新建一个app项目cd learn_modelspython manage.py startapp learn此时目…

未来五年有颠覆性的IT技术都在这里

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删据福布斯杂志报道&#xff0c;在美国奥兰多举行的Gartner研讨会上&#xff0c;市场研究机构Gartner Research的副总裁兼资深研究员大卫卡利&…

java ee maven_真正释放Maven和Java EE的强大功能

java ee maven如果野心和愿景太复杂而无法使用&#xff0c;则它们可能会淘汰伟大的解决方案。 尽管Maven和Java EE是在整个Java行业中都已建立的良好技术&#xff0c;但是使用它们并使用其作者打算使用的所有技术和模式来设计项目可能非常棘手。 在开发过程中途&#xff0c;由…

python字符串解释_python基础之字符串详解

1、Python环境配置&#xff1a;下载好之后安装&#xff0c;注意勾选环境变量。2、写python一定要注意代码的缩进。2、字符串&#xff1a;(1)、字符串是从左到右是从0开始索引&#xff0c;从右到左是从-1开始。遵循包前不包后原则。举例说明&#xff1a;代码&#xff1a; …

程序员们,想在双十一脱单?赶快跟我捯饬起来吧

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删生活中有很多男人一边抱怨自己不够洋气&#xff0c;找不到女票&#xff0c;另一方面又懒到宁肯在床上撸啊撸&#xff0c;也不愿意好好打扮自己。…

jboss8日志级别设置_罐中研讨会:设置JBoss BRMS全日研讨会

jboss8日志级别设置是否在寻找一种简单的方法来宣传&#xff0c;展示或演示使用JBoss业务规则管理系统&#xff08;BRMS&#xff09;产品的入门难度&#xff1f; 别无所求&#xff0c;因为我们已经召集了这个研讨会&#xff0c;因此您可以围绕JBoss BRMS构建一个晚上&#xff…

python具有伪代码的本质吗_Python的优点之一是具有伪代码的本质。( )_学小易找答案...

【单选题】下面关于函数的说法,错误的是( )。【单选题】实际开发中,文件或者文件夹操作都要用到os模块。( )【单选题】函数能处理比声明时更多的参数,它们是( ) 参数。【单选题】函数的名称可以随意命名。( )【单选题】Python源代码被解释器转换后的格式为( )。【单选题】Pytho…

C语言编程时你常犯的18种错误

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删C语言的最大特点是&#xff1a;功能强、使用方便灵活。C编译的程序对语法检查并不象其它高级语言那么严格&#xff0c;这就给编程人员留下“灵活…

python字典items返回什么_Python 字典items返回列表,iteritems返回迭代器

说明&#xff1a;items以列表方式返回字典中的键值对&#xff0c;iteritems以迭代器对象 返回键值对儿(Python3中不再支持)&#xff1b;字典items()方法和iteritems()方法&#xff0c;是python字典的内建函数&#xff0c;分别会返回列表和迭代器&#xff0c;下面一起来看下字典…

pl/postgresql_将PostgreSQL PL / Java安装为PostgreSQL扩展

pl/postgresql在2011年&#xff0c;我在PostgreSQL PL / Java上撰写了一系列文章。 基本信息仍然可靠&#xff0c;但是现在有了一种从源代码安装PL / Java的简便得多的方法。 这也消除了依赖第三方来创建软件包的需要。 由于我的读者已经熟悉git和maven&#xff0c;因此这些注释…

这些知识你都不知道,难怪说你学不懂C语言!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删关于C语言的那些小知识&#xff0c;准备学习或者刚刚入门的你已经了解了吗&#xff1f;语言种类编译语言静态声明语言面向过程的编程语言环境工具…

图片识别出处_AI人脸识别

前言最近网络上爆火的藏族小哥哥丁真&#xff0c;大家都知道吗&#xff1f;十几天前凭借一张纯真、干净、帅气的脸霸屏各大短视频平台&#xff0c;连各大电视台新闻媒体都争相报道&#xff0c;这个藏族小伙瞬间火了&#xff01;&#xff01;网友们对于丁真的长相评价不一&#…

java源文件编译成jar_从源文件和JAR文件构建Java代码模型

java源文件编译成jar最近&#xff0c;我花了一些时间来研究有效java &#xff0c;该方法正在GitHub上达到300星&#xff08;可以免费帮助实现目标&#xff1a;D&#xff09;。 Effectivejava是在您的Java代码上运行查询的工具。 它基于我参与的另一个项目javaparser 。 Javapa…

【从零开始学C语言】知识总结一:C语言的基本知识汇总

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删C语言是一种计算机程序设计语言。它既有高级语言的特点&#xff0c;又具有汇编语言的特点。它可以作 为系统设计语言&#xff0c;编写工作系统应…

排球分组循环交叉编排_同学!中国海洋大学第一届排球联赛等你来战!

New中国海洋大学第一届排球联赛开始啦比赛宗旨1亲爱的同学们&#xff1a;为增强学生凝聚力&#xff0c;加强新老生交流&#xff0c;促进各院系的友谊&#xff0c;培养同学们的团队精神&#xff0c;丰富同学们的课余生活&#xff0c;展示我校文体风采&#xff0c;特此举办本次中…

jolokia_使用WildFly 9和Jolokia监视DevOps样式

jolokiaDevOps是当今最热门的话题之一。 并且围绕它的广泛主题使您很难真正找到完整的描述或涵盖体面粒度的所有内容。 可以肯定的一件事是&#xff1a;最重要的部分之一是提供正确的度量标准和信息以监视应用程序。 Java EE和JMX 监视Java EE服务器的标准方法是JMX。 使用JCo…

计算机的本质是哲学

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删学什么抽象模型庄子说过吾生有崖&#xff0c;知无涯。以有限的生命去学习无尽的知识是很愚蠢的。所以&#xff0c;学习的终极目标一定不是知识本…