找不到libmmd.dll无法继续执行代码_300 行代码带你秒懂 Java 多线程!| 原力计划...

15842d9f203e320b1b73d449d0a5f1b5.gif

f831c6b1be59dbff4686a3ce0c4a80ac.png

作者 | 永远在路上【】

责编 | 胡巍巍

出品 | CSDN博客

a26061de10cd53b5a95fe32addc6866d.png线程线程的概念,百度是这样解释的:线程(英语:Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(Lightweight Processes),但轻量进程更多指内核线程(Kernel Thread),而把用户线程(User Thread)称为线程。1.1 线程与进程的区别3bd61c3d1227be0fc9a28802f61963a4.png进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。也就是,进程可以包含多个线程,而线程是程序执行的最小单位。1.2 线程的状态6b68ada25f31aad2fb6e1cedb177877f.png
  • NEW:线程刚创建
  • RUNNABLE: 在JVM中正在运行的线程,其中运行状态可以有运行中RUNNING和READY两种状态,由系统调度进行状态改变。
  • BLOCKED:线程处于阻塞状态,等待监视锁,可以重新进行同步代码块中执行
  • WAITING : 等待状态
  • TIMED_WAITING: 调用sleep() join() wait()方法可能导致线程处于等待状态
  • TERMINATED: 线程执行完毕,已经退出
1.3 Notify和Wait :Notify和Wait 的作用首先看源码给出的解释,这里翻译了一下:Notify:唤醒一个正在等待这个对象的线程监控。如果有任何线程正在等待这个对象,那么它们中的一个被选择被唤醒。选择是任意的,发生在执行的酌情权。一个线程等待一个对象通过调用一个{@code wait}方法进行监视。Notify()需要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁Wait:导致当前线程等待,直到另一个线程调用{@link java.lang.Object#notify()}方法或{@link java.lang.Object#notifyAll()}方法。换句话说,这个方法的行为就像它简单一样执行调用{@code wait(0)}。当前线程必须拥有该对象的监视器。线程释放此监视器的所有权,并等待另一个线程通知等待该对象的监视器的线程,唤醒通过调用{@code notify}方法或{@code notifyAll}方法。然后线程等待,直到它可以重新取得监视器的所有权,然后继续执行。Wait()的作用是使当前执行代码的线程进行等待,它是Object类的方法,该方法用来将当前线程置入预执行队列中,并且在Wait所在的代码行处停止执行,直到接到通知或被中断为止。在调用Wait方法之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用Wait方法。Wait和Sleep的区别:
  • 它们最大本质的区别是,Sleep()不释放同步锁,Wait()释放同步锁。
  • 还有用法的上的不同是:Sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用Interreput()来强行打断;Wait()可以用Notify()直接唤起。
  • 这两个方法来自不同的类分别是Thread和Object
  • 最主要是Sleep方法没有释放锁,而Wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
1.4 Thread.sleep() 和Thread.yield()的异同
  • 相同 :Sleep()和yield()都会释放CPU。
  • 不同:Sleep()使当前线程进入停滞状态,所以执行Sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。Sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。
1.5 补充:死锁的概念死锁:指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。死锁产生的四个必要条件(缺一不可):
  • 互斥条件:顾名思义,线程对资源的访问是排他性,当该线程释放资源后下一线程才可进行占用。
  • 请求和保持:简单来说就是自己拿的不放手又等待新的资源到手。线程T1至少已经保持了一个资源R1占用,但又提出对另一个资源R2请求,而此时,资源R2被其他线程T2占用,于是该线程T1也必须等待,但又对自己保持的资源R1不释放。
  • 不可剥夺:在没有使用完资源时,其他线性不能进行剥夺。
  • 循环等待:一直等待对方线程释放资源。
我们可以根据死锁的四个必要条件破坏死锁的形成。1.6 补充:并发和并行的区别并发:是指在某个时间段内,多任务交替的执行任务。当有多个线程在操作时,把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行。在一个时间段的线程代码运行时,其它线程处于挂起状。并行:是指同一时刻同时处理多任务的能力。当有多个线程在操作时,CPU同时处理这些线程请求的能力。区别就在于CPU是否能同时处理所有任务,并发不能,并行能。1.7 补充:线程安全三要素
  • 原子性:Atomic包、CAS算法、Synchronized、Lock。
  • 可见性:Synchronized、Volatile(不能保证原子性)。
  • 有序性:Happens-before规则。
1.8 补充:如何实现线程安全
  • 互斥同步:Synchronized、Lock。
  • 非阻塞同步:CAS。
  • 无需同步的方案:如果一个方法本来就不涉及共享数据,那它自然就无需任何同步操作去保证正确性。
1.9 补充:保证线程安全的机制:
  • Synchronized关键字
  • Lock
  • CAS、原子变量
  • ThreadLocl:简单来说就是让每个线程,对同一个变量,都有自己的独有副本,每个线程实际访问的对象都是自己的,自然也就不存在线程安全问题了。
  • Volatile
  • CopyOnWrite写时复制
随着CPU核心的增多以及互联网迅速发展,单线程的程序处理速度越来越跟不上发展速度和大数据量的增长速度,多线程应运而生,充分利用CPU资源的同时,极大提高了程序处理速度。14419c57fc5796c5d458d1167c00ddb6.png创建线程的方法继承Thread类:
public class ThreadCreateTest {public static void main(String[] args) {new MyThread().start();
    }
}class MyThread extends Thread {@Overridepublic void run() {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
    }
}
实现Runable接口:
public class RunableCreateTest {public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();new Thread(runnable).start();
    }
}class MyRunnable implements Runnable {@Overridepublic void run() {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
    }
}
通过Callable和Future创建线程:
public class CallableCreateTest {public static void main(String[] args) throws Exception {// 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        FutureTask futureTask = new FutureTask<>(callable);new Thread(futureTask).start();// get方法会阻塞调用的线程
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
    }
}class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");int sum = 0;for (int i = 0; i <= 100000; i++) {
            sum += i;
        }
        Thread.sleep(5000);
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");return sum;
    }
}
线程池方式创建:实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承,但可以多实现啊),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。实际开发中,阿里巴巴开发插件一直提倡使用线程池创建线程,原因在下方会解释,所以上面的代码我就只简写了一些Demo。2.1 线程池创建线程线程池,顾名思义,线程存放的地方。和数据库连接池一样,存在的目的就是为了较少系统开销,主要由以下几个特点:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗(主要)。提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。Java提供四种线程池创建方式:
  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
通过源码我们得知ThreadPoolExecutor继承自AbstractExecutorService,而AbstractExecutorService实现了ExecutorService。
public class ThreadPoolExecutor extends AbstractExecutorServicepublic abstract class AbstractExecutorService implements ExecutorService
e4e5524e7b05aca894620c68116d7f46.png2.2 ThreadPoolExecutor介绍实际项目中,用的最多的就是ThreadPoolExecutor这个类,而《阿里巴巴Java开发手册》中强制线程池不允许使用Executors去创建,而是通过New ThreadPoolExecutor实例的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。fc29a0545390fa2c7b506ffcd168b2a8.png我们从ThreadPoolExecutor入手多线程创建方式,先看一下线程池创建的最全参数。
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {if (corePoolSize 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize             keepAliveTime 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;
    }
参数说明如下:
  • corePoolSize:线程池的核心线程数,即便线程池里没有任何任务,也会有corePoolSize个线程在候着等任务。
  • maximumPoolSize:最大线程数,不管提交多少任务,线程池里最多工作线程数就是maximumPoolSize。
  • keepAliveTime:线程的存活时间。当线程池里的线程数大于corePoolSize时,如果等了keepAliveTime时长还没有任务可执行,则线程退出。
  • Unit:这个用来指定keepAliveTime的单位,比如秒:TimeUnit.SECONDS。
  • BlockingQueue:一个阻塞队列,提交的任务将会被放到这个队列里。
  • threadFactory:线程工厂,用来创建线程,主要是为了给线程起名字,默认工厂的线程名字:pool-1-thread-3。
  • handler:拒绝策略,当线程池里线程被耗尽,且队列也满了的时候会调用。
2.2.1BlockingQueue对于BlockingQueue个人感觉还需要单独拿出来说一下。BlockingQueue:阻塞队列,有先进先出(注重公平性)和先进后出(注重时效性)两种,常见的有两种阻塞队列:ArrayBlockingQueue和LinkedBlockingQueue队列的数据结构大致如图:22239b36757f59ad676d5b6531a6aff4.png队列一端进入,一端输出。而当队列满时,阻塞。BlockingQueue核心方法:1. 放入数据put2. 获取数据take。常见的两种Queue:2.2.2 ArrayBlockingQueue基于数组实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。一段代码来验证一下:
    package map;import java.util.concurrent.*;public class MyTestMap {// 定义阻塞队列大小private static final int maxSize = 5;public static void main(String[] args){
            ArrayBlockingQueue queue = new ArrayBlockingQueue(maxSize);new Thread(new Productor(queue)).start();new Thread(new Customer(queue)).start();
        }
    }class Customer implements Runnable {private BlockingQueue queue;
        Customer(BlockingQueue queue) {this.queue = queue;
        }
        @Overridepublic void run() {this.cusume();
        }private void cusume() {while (true) {try {int count = (int) queue.take();
                    System.out.println("customer正在消费第" + count + "个商品===");// 只是为了方便观察输出结果
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }class Productor implements Runnable {private BlockingQueue queue;private int count = 1;
        Productor(BlockingQueue queue) {this.queue = queue;
        }
        @Overridepublic void run() {this.product();
        }private void product() {while (true) {try {queue.put(count);
                    System.out.println("生产者正在生产第" + count + "个商品");
                    count++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }//输出如下/**
生产者正在生产第1个商品
生产者正在生产第2个商品
生产者正在生产第3个商品
生产者正在生产第4个商品
生产者正在生产第5个商品
customer正在消费第1个商品===
*/
2.2.3 LinkedBlockingQueue基于链表的阻塞队列,内部也维护了一个数据缓冲队列。需要我们注意的是如果构造一个LinkedBlockingQueue对象,而没有指定其容量大小。LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。2.2.4 LinkedBlockingQueue和ArrayBlockingQueue的主要区别
  • ArrayBlockingQueue的初始化必须传入队列大小,LinkedBlockingQueue则可以不传入。
  • ArrayBlockingQueue用一把锁控制并发,LinkedBlockingQueue俩把锁控制并发,锁的细粒度更细。即前者生产者消费者进出都是一把锁,后者生产者生产进入是一把锁,消费者消费是另一把锁。
  • ArrayBlockingQueue采用数组的方式存取,LinkedBlockingQueue用Node链表方式存取。
2.2.5handler拒绝策略Java提供了4种丢弃处理的方法,当然你也可以自己实现,主要是要实现接口:RejectedExecutionHandler中的方法。
  • AbortPolicy:不处理,直接抛出异常。
  • CallerRunsPolicy:只用调用者所在线程来运行任务,即提交任务的线程。
  • DiscardOldestPolicy:LRU策略,丢弃队列里最近最久不使用的一个任务,并执行当前任务。
  • DiscardPolicy:不处理,丢弃掉,不抛出异常。
2.2.6线程池五种状态
    private static final int RUNNING    = -1 <    private static final int SHUTDOWN   =  0 <    private static final int STOP       =  1 <    private static final int TIDYING    =  2 <    private static final int TERMINATED =  3 <

RUNNING:在这个状态的线程池能判断接受新提交的任务,并且也能处理阻塞队列中的任务。

SHUTDOWN:处于关闭的状态,该线程池不能接受新提交的任务,但是可以处理阻塞队列中已经保存的任务,在线程处于RUNNING状态,调用shutdown()方法能切换为该状态。

STOP:线程池处于该状态时既不能接受新的任务也不能处理阻塞队列中的任务,并且能中断现在线程中的任务。当线程处于RUNNING和SHUTDOWN状态,调用shutdownNow()方法就可以使线程变为该状态。

TIDYING:在SHUTDOWN状态下阻塞队列为空,且线程中的工作线程数量为0就会进入该状态,当在STOP状态下时,只要线程中的工作线程数量为0就会进入该状态。

TERMINATED:在TIDYING状态下调用terminated()方法就会进入该状态。可以认为该状态是最终的终止状态。

回到线程池创建ThreadPoolExecutor,我们了解了这些参数,再来看看ThreadPoolExecutor的内部工作原理:239ad8d00a3363feb8a52caa7fb269b9.png
  • 判断核心线程是否已满,是进入队列,否:创建线程
  • 判断等待队列是否已满,是:查看线程池是否已满,否:进入等待队列
  • 查看线程池是否已满,是:拒绝,否创建线程
2.3深入理解ThreadPoolExecutor进入Execute方法可以看到:
  public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();//判断当前活跃线程数是否小于corePoolSize,如果小于,则调用addWorker创建线程执行任务if (workerCountOf(c)             if (addWorker(command, true))return;
            c = ctl.get();
        }//如果不小于corePoolSize,则将任务添加到workQueue队列。if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))
                reject(command);else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }//如果放入workQueue失败,则创建线程执行任务,如果这时创建线程失败(当前线程数不小于maximumPoolSize时),就会调用reject(内部调用handler)拒绝接受任务。else if (!addWorker(command, false))
            reject(command);
    }
AddWorker方法:
  • 创建Worker对象,同时也会实例化一个Thread对象。在创建Worker时会调用threadFactory来创建一个线程。
  • 然后启动这个线程。
2.3.1线程池中CTL属性的作用是什么?看源码第一反应就是这个CTL到底是个什么东东?有啥用?一番研究得出如下结论:CTL属性包含两个概念:
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));private static int ctlOf(int rs, int wc) { return rs | wc; }
  • runState:即rs 表明当前线程池的状态,是否处于Running,Shutdown,Stop,Tidying。
  • workerCount:即wc表明当前有效的线程数。
我们点击workerCount即工作状态记录值,以RUNNING为例,RUNNING = -1 << COUNT_BITS;,即-1无符号左移COUNT_BITS位,进一步我们得知COUNT_BITS位29,因为Integer位数为31位(2的五次方减一)
    private static final int COUNT_BITS = Integer.SIZE - 3;
既然是29位那么就是Running的值为:
1110 0000 0000 0000 0000 0000 0000 0000 |||
31~29位
那低28位呢,就是记录当前线程的总线数啦:
    // Packing and unpacking ctlprivate static int runStateOf(int c)     { return c & ~CAPACITY; }private static int workerCountOf(int c)  { return c & CAPACITY; }private static int ctlOf(int rs, int wc) { return rs | wc; }
从上述代码可以看到workerCountOf这个函数传入ctl之后,是通过CTL&CAPACITY操作来获取当前运行线程总数的。也就是RunningState|WorkCount&CAPACITY,算出来的就是低28位的值。因为CAPACITY得到的就是高3位(29-31位)位0,低28位(0-28位)都是1,所以得到的就是ctl中低28位的值。而runStateOf这个方法的话,算的就是RunningState|WorkCount&CAPACITY,高3位的值,因为CAPACITY是CAPACITY的取反,所以得到的就是高3位(29-31位)为1,低28位(0-28位)为0,所以通过&运算后,所得到的值就是高3为的值。简单来说就是ctl中是高3位作为状态值,低28位作为线程总数值来进行存储。2.3.2 shutdownNow和shutdown的区别看源码发现有两种近乎一样的方法,shutdownNow和shutdown,设计者这么设计自然是有它的道理,那么这两个方法的区别在哪呢?
  • shutdown会把线程池的状态改为SHUTDOWN,而shutdownNow把当前线程池状态改为STOP。
  • shutdown只会中断所有空闲的线程,而shutdownNow会中断所有的线程。
  • shutdown返回方法为空,会将当前任务队列中的所有任务执行完毕;而shutdownNow把任务队列中的所有任务都取出来返回。
2.3.3 线程复用原理
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;try {while (task != null || (task = getTask()) != null) {
                w.lock();// If pool is stopping, ensure thread is interrupted;// if not, ensure thread is not interrupted.  This// requires a recheck in second case to deal with// shutdownNow race while clearing interruptif ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }
就是任务在并不只执行创建时指定的firstTask第一任务,还会从任务队列的中自己主动取任务执行,而且是有或者无时间限定的阻塞等待,以保证线程的存活。默认的是不允许。2.4 CountDownLatch和CyclicBarrier区别

countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次。

CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供Reset功能,可以多次使用。

3. 多线程间通信的几种方式提及多线程又不得不提及多线程通信的机制。首先,要短信线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析:题目:有两个线程A、B,A线程向一个集合里面依次添加元素"abc"字符串,一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作。3.1使用volatile关键字
package thread;/**
 * 
 * @author hxz
 * @description 多线程测试类
 * @version 1.0
 * @data 2020年2月15日 上午9:10:09
 */public class MyThreadTest {public static void main(String[] args) throws Exception {
        notifyThreadWithVolatile();
    }/**
     * 定义一个测试
     */private static volatile boolean flag = false;/**
     * 计算I++,当I==5时,通知线程B
     * @throws Exception
     */private static void notifyThreadWithVolatile() throws Exception {
        Thread thc = new Thread("线程A"){@Overridepublic void run() {for (int i = 0; i 10; i++) {if (i == 5) {
                        flag = true;try {
                            Thread.sleep(500L);
                        } catch (InterruptedException e) {// TODO Auto-generated catch block
                            e.printStackTrace();
                        }break;
                    }
                    System.out.println(Thread.currentThread().getName() + "====" + i);
                }
            }
        };
        Thread thd = new Thread("线程B") {@Overridepublic void run() {while (true) {// 防止伪唤醒 所以使用了whilewhile (flag) {
                        System.out.println(Thread.currentThread().getName() + "收到通知");
                        System.out.println("do something");try {
                            Thread.sleep(500L);
                        } catch (InterruptedException e) {// TODO Auto-generated catch block
                            e.printStackTrace();
                        }return ;
                    }
                }
            }
        };
        thd.start();
        Thread.sleep(1000L);
        thc.start();
    }
}
个人认为这是基本上最好的通信方式,因为A发出通知B能够立马接受并Do Something。原文链接:https://blog.csdn.net/weixin_44104367/article/details/104481510【End】

《原力计划【第二季】- 学习力挑战》正式开始!
即日起至 3月21日,千万流量支持原创作者,更有专属【勋章】等你来挑战

d03ed2c27f4514f8c0a3e3e4cf882cf0.png推荐阅读 ☞深度好文 | 中间人攻击、ARP欺骗背后的原理及漏洞还原☞全方位解析阿里云核心技术竞争力,CSDN 独家在线峰会来了!

☞用于小型图形挖掘研究的瑞士军刀:空手道俱乐部的图表学习Python库

☞罗永浩欲直播带货,京东说可以帮忙联系

☞MySQL数据库无完整备份删库,除了跑路还能怎么办?

☞Libra新编程语言 :Move 的所有权模型灵感来源原来是它……

59a6bd1f992fde9819794beca3b52595.png你点的每一个在看,我认真当成了喜欢

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

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

相关文章

苹果、联想及华硕均看准美国电脑运输的增长

据国外媒体雅虎金融报道&#xff0c;根据国际数据公司的研究&#xff0c;美国个人电脑在4Q14中下跌至1820万台&#xff0c;在4Q15中下跌至1740万台&#xff0c;跌幅4.3%。而苹果、联想和华硕的产品出货量却呈现上市趋势。苹果出货量上升8.9%&#xff0c;至220万台&#xff0c;华…

如何升级浏览器_前谷歌员工爆料:谷歌工程师们是如何合谋“杀死”IE6浏览器的...

浏览器在互联网中的地位可见一斑&#xff0c;甚至可以说&#xff0c;它是比搜索引擎和社交软件更强的流量入口。微软IE6当年在2001年作为Windows XP的默认浏览器发布&#xff0c;比Chrome首次发布还要早六年。 但是&#xff0c;谷歌Chrome却后来居上&#xff0c;如今的市场份额…

安卓设备刷linux发行版,绝对精华,大牛教你在Android系统上安装linux发行版

Install linux distribution(Debian/Ubuntu/Kali Linux/Fedora/openSUSE/Gentoo/RootFS/Arch Linux) on Android system在Android系统上安装linux发行版(Debian/Ubuntu/Kali Linux/Fedora/openSUSE/Gentoo/RootFS/Arch Linux)1、所用的手机类型为Samsung Note2 Verizon i6052、…

在 ASP.NET Core 中使用 HTTP 标头传播

前言我们常用 JWT 令牌用于身份验证&#xff0c;前端一般是在请求中包含 HTTP 标头 Authorization 实现。但是&#xff0c;当服务间需要互相调用时&#xff0c;也需要"按原样"将标头传播到目标服务。原来的解决方案是从请求中读取标头&#xff0c;并将其添加到对外请…

中英文标点符号切换的组合键_易混标点符号:一字线(—)、短横线(-)、浪纹线(~)...

前情提要&#xff1a;上次辨析了容易混淆的中英文冒号&#xff08;&#xff1a;、:&#xff09;、比号&#xff08;∶&#xff09;【点此查看】&#xff0c;这次继续介绍易混标点符号。易混标点符号&#xff1a;一字线&#xff08;—&#xff09;、短横线&#xff08;-&#xf…

Linux命令-网络命令:wall

wall hello word 向所有登录用户发送消息hello world root用户自己也会收到消息,wangyunpeng用户收到消息如下图:

win定时关机_两种方法让你设置电脑定时关机

方法一&#xff1a;利用计划程序步骤一&#xff1a;在开始菜单搜索框中输入计划任务&#xff0c;点击任务计划程序步骤二&#xff1a;点击操作再点击创建基本任务创建基本任务中输入名称和相关描述步骤三&#xff1a;触发器选择为每天&#xff0c;然后点击下一步步骤四&#xf…

AsyncEx - async/await 的辅助库

简介AsyncEx - async/await 的辅助库安装使用Nuget安装Nito.AsyncEx使用AsyncLock构造AsyncLock函数可以采用异步等待队列&#xff1b;传递自定义等待队列以指定您自己的排队逻辑。private readonly AsyncLock _mutex new AsyncLock(); public async Task UseLockAsync() {// …

dell设置从ssd启动_为什么懂电脑的人都说SSD不要分区?原来真相是这样!

最近韩博士打开电脑时发现开机速度真是越来越慢&#xff0c;从一开始的十秒左右到现在居然要一分多钟才能进入桌面&#xff01;果然是老了。花费一天的时间终于将电脑清理个干净&#xff0c;原以为能够缓解开机慢的情况&#xff0c;结果还是一样&#xff0c;等到地老天荒才看到…

数据切分——Atlas介绍

Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上&#xff0c;修改了大量bug&#xff0c;添加了很多功能特性。目前该项目在360公司内部得到了广泛应用&#xff0c;很多MySQL业务…

在Arcmap中加载互联网地图资源的4种方法

在Arcmap中加载互联网地图资源的4种方法 前一段时间想在Arcmap中打开互联网地图中的地图数据&#xff0c;如影像数据、基础地图数据等&#xff0c;经过简单研究目前总结了四种方法&#xff0c;整理下与大家分享&#xff0c;有些内容可能理解有误&#xff0c;希望大家多多指教。…

iOS开发之手势识别

感觉有必要把iOS开发中的手势识别做一个小小的总结。在上一篇iOS开发之自定义表情键盘(组件封装与自动布局)博客中用到了一个轻击手势&#xff0c;就是在轻击TextView时从表情键盘回到系统键盘&#xff0c;在TextView中的手是用storyboard添加的。下面会先给出如何用storyboard…

WPF 基础控件之 GroupBox样式

其他基础控件1.Window2.Button3.CheckBox4.ComboBox5.DataGrid 6.DatePicker7.ExpanderGroupBox控件修改Style需要注意使用Grid分两行进行展示第0行显示Header第1行显示Content。Header&#xff1a;添加Border并边框BorderThickness"1" 内部新增 ContentPresenter 然…

并联系统的失效率公式推导_供暖系统水力平衡率对室温的影响

摘要&#xff1a;热水供暖系统设计&#xff0c;为了保证室内能够达到设计温度&#xff0c;必须使流进散热器的热水流量与房间的热负荷相匹配&#xff0c;散热器才能散发足够热量以弥补由于建筑物围护结构散失的热量&#xff0c;保证室内温度。供暖系统设计只有通过正确的水力计…

面向对象——一起来复习托付与事件!

事件与托付事实上并不难理解。仅仅是由于它们的使用方式与经常使用的编码有非常大的区别&#xff0c;例如通常编写的都是同步代码&#xff0c;调用一个类型的方法&#xff0c;会即刻出现方法运行的结果。这是符合逻辑的。但在某些情况中&#xff0c;同步代码未必满足需求&#…

Blazor University (7)组件 — 双向绑定

原文链接&#xff1a;https://blazor-university.com/components/two-way-binding/双向绑定源代码[1]注意&#xff1a; 如果您还没有这样做过&#xff0c;请在继续本节之前先执行单向绑定[2]中的步骤。到目前为止&#xff0c;我们有一个包含嵌入组件的页面&#xff0c;并且我们…

【iCore3 双核心板】例程二十二:LAN_UDP实验——以太网数据传输

实验指导书及代码包下载&#xff1a; http://pan.baidu.com/s/1kTPlJMJ iCore3 购买链接&#xff1a; https://item.taobao.com/item.htm?id524229438677 转载于:https://www.cnblogs.com/xiaomagee/p/5084291.html

tomcat出现5个using_当猫咪出现这5个迹象,主人就要给猫咪换猫粮了

养宠的朋友们你们知道吗&#xff1f;猫咪最好是要定期换粮&#xff0c;这样才有助于猫咪营养平衡&#xff0c;并且避免猫咪对单一食物感到厌烦哦&#xff01;但是应该多久给猫咪换一次粮呢&#xff1f;如果你家猫咪出现这5个迹象时&#xff0c;那就是提醒你需要更换猫粮了&…

C# Barrier类

对于同步&#xff0c;Barrier 类非常适用于其中工作有多个任务分支且以后又需要合并工作的情况。Barrier 类用于需要同步的参与者。激活一个任务时&#xff0c;就可以动态地添加其他参与者&#xff0c;例如&#xff0c;从父任务中创建子任务。参与者在继续之前&#xff0c;可以…

Android版哆啦A梦连连看游戏源码完整版

本代码主本人编写&#xff0c;没版权问题&#xff0c;另有其他少量小游戏和应用源码稍后会陆续上线!哆啦A梦连连看包括了2种游戏模式和60关卡&#xff0c;并可以通过修改配置文件很方便的实现自行增加新关卡。采用andengine游戏引擎开发&#xff0c;内置了趣米广告和用户统计fl…