详解线程池

概念:

什么是线程池:

线程池是用来存储多线程的容器,是一种处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。

线程池使用和不使用的区别:

  1. 因为系统创建线程池的成本很高,会涉及到和操作系统交互,频繁的创建线程和销毁会对消耗系统资源
  2. 线程池会启动一个线程执行这个任务,如果不够可以自动加,执行完线程会进入空闲状态,不会销毁,等待下一次执行(很乖的)

不使用线程池会造成资源浪费

我们创建一个线程执行任务后线程死亡.如果线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
比如:中午吃完饭将碗洗干净,晚上接着使用 重复利用,可以节省资源

线程状态:

在这里插入图片描述

线程状态具体含义
NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程对象,没有线程特征。
RUNNABLE当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的调度。
BLOCKED当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态
四种线程池:
方法名说明
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
线程池常用方法:
方法说明
submit()使用完毕归还线程
shutdown()关闭线程池
newCachedThreadPool:

构造方法

方法名说明
newCachedThreadPool()创建一个线程池,默认为空,最大容量是int最大值
newCachedThreadPool​(ThreadFactory threadFactory)创建一个根据需要创建新线程的线程池,但在它们可用时将重用以前构造的线程,并在需要时使用提供的ThreadFactory创建新线程。
代码演示:
    public static void main(String[] args) throws InterruptedException {/**创建一个默认的线程池对象.池子中默认是空的.默认最多可以容纳int类型的最大值idea会提醒你,手动创建会更好,这里的初始值是最大值,最大多少个线程Executors:创建线程池对象ExecutorService:控制线程池*/ExecutorService es = Executors.newCachedThreadPool();// submit:使用完毕归还线程es.submit(() -> System.out.println(Thread.currentThread().getName() + ": 执行"));/**这里让线程睡眠会导致只有一条线程运行原因:创建的时候没有指定线程,所以会自动创建一条线程,执行完放回线程池,然后睡眠完了发现线程池有刚才闲置的线程就直接用了不睡眠为什么会创建两个:先自动创建,使用完还没有来得及归还,代码就创建下一个线程了但是睡眠时间比较少的话,比如sleep(1),那么还是会创建两个线程*/Thread.sleep(1000);es.submit(() -> System.out.println(Thread.currentThread().getName() + ": 执行"));// 关闭线程池es.shutdown();}
newFixedThreadPool:

代码演示:

    public static void main(String[] args) {// 参数不是初始值而是最大值ExecutorService es = Executors.newFixedThreadPool(10);System.out.println(((ThreadPoolExecutor) es).getPoolSize());// 0es.submit(() -> System.out.println(Thread.currentThread().getName() + "在执行了"));es.submit(() -> System.out.println(Thread.currentThread().getName() + "在执行了"));System.out.println(((ThreadPoolExecutor) es).getPoolSize());// 2es.shutdown();}
ThreadPoolExecutor自定义线程池:

参数详解:

参数一:核心线程数量
参数二:最大线程数量
参数三:空闲线程最大存活时间
参数四:时间单位,对应参数三的
参数五:任务列表(阻塞队列):让任务在队列中等,等到线程有空,再从队列中获取任务执行
参数六:创建线程工厂:按照默认的方式创建线程对象
参数七:任务的拒绝策略:

  1. 什么时候拒绝:提交的任务 > (池子中最大线程数 + 队列容量)
  2. 如何拒绝:看下面的四种拒绝策略

线程类:

public class Runn implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行了");}
}

测试类:

public class Demo05 {public static void main(String[] args) {ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());tpe.submit(new Runn());tpe.submit(new Runn());tpe.shutdown();}
}
任务拒绝策略:
方法名说明
ThreadPoolExecutor.AbortPolicy丢弃任务并抛出RejectedExecutionException异常。是默认的拒绝策略,可灵活回收空闲线程,若无可回收,则新建线程
ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常 这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy抛弃队列中等待最久的任务 然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunsPolicy调用任务的run()方法绕过线程池直接执行
public class Demo {public static void main(String[] args) {/*ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 2,TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());*//* ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 2,TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());*/// 如果是最大线程数是3,队列是1,一共是4,创建10个线程,那么使用此拒绝策略,会打印,4个,但是打印的是线程1、2、3、10,10前面的就不要了/* ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 2,TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());*/// 任务过多的时候直接缇跳过线程池让main方法执行多出的线程ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 2,TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 16; i++) {tpe.submit(new Runn());}tpe.shutdown();}
}
volatile:

Volatile关键字 : 强制线程每次在使用的时候,都会看一下共享区域最新的,但是不能不能保证原子性

使用场景:加在共享数据上

当A线程修改了共享数据时,B线程没有及时获取到最新的值,如果还在使用原先的值,就会出现问题

  1. 堆内存是唯一的,每一个线程都有自己的线程栈。
  2. 每一个线程在使用堆里面变量的时候,都会先拷贝一份到变量的副本中。
  3. 在线程中,每一次使用是从变量的副本中获取的。

定义循环测试,如果没有获取最新数据就会一直循环

共享数据类:

public class Share {public static  int MONEY =10;
}

定义两个线程类:

public class libai extends Thread {@Overridepublic void run() {while (Share.MONEY = 1000) {}System.out.println("钱发生了变化");}
}
public class hanxin extends Thread {@Overridepublic void run() {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Share.MONEY = 900;}
}

测试类:

public class Demo04 {public static void main(String[] args) {hanxin t1 = new hanxin();t1.setName("韩信");t1.start();libai t2 = new libai();t2.setName("李白");t2.start();}
}

解决方案:
在共享数据上加上volatile就可以了

public class Share {public static volatile int MONEY =10;
}
synchronized:

上面的情况用synchronized也是可以解决的
原因是:

  1. synchronized会清空变量副本
  2. 拷贝共享变量最新的值到变量副本中
  3. 如果修改了共享数据,会把修改后的变量副本中的值赋值给共享数据

共享数据类:

public class Share {public static Object lock = new Object();public static volatile int MONEY = 10;
}

两个线程类:

public class hanxin extends Thread {@Overridepublic void run() {while (true) {synchronized (Share.lock) {if (Share.MONEY != 10) {System.out.println("数值发生变化");break;}}}}
}
public class libai extends Thread {@Overridepublic void run() {synchronized (Share.lock) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Share.MONEY = 1000;}}
}

测试类:

public class Demo04 {public static void main(String[] args) {hanxin t1 = new hanxin();t1.setName("韩信");t1.start();libai t2 = new libai();t2.setName("李白");t2.start();}
}
原子性AtomicInteger:
  • 原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。
  • volatile只能保证线程每次在使用共享数据的值是最新的,但是不能保证原子性
  • AtomicInteger原理 : 自旋锁 + CAS 算法
  • CAS算法:
    • 有3个操作数(内存值V, 旧的预期值A,要修改的值B)
    • 当旧的预期值A == 内存值 此时修改成功,将V改为B
    • 当旧的预期值A!=内存值 此时修改失败,不做任何操作
    • 并重新获取现在的最新值(这个重新获取的动作就是自旋)
  • 自旋:
    • 在修改共享数据的时候,先把原来的旧值记录下来,然后要修改时候如果内存中和旧值的一样证明其他线程没操作内存值,那就修改成功,如果不一样说明其他线程操作了,就失败,会把最新的值从内存获取到旧值,然后再修改,重新获取就是自旋

例:

public class Demo06 implements Runnable {private int count = 0;@Overridepublic void run() {for (int i = 0; i < 100; i++) {/*   1、从共享数据中读取数据到本地线程栈中2、修改本线程栈中的变量副本值3、会把本线程栈中变量副本值赋值给共享数据异常:1、线程A刚修改了本线程栈中的变量副本值为101,还没同步给共享数据2、这时候线程B抢走了CPU的执行权,也修改了本线程栈中的变量副本值为101,然后同步给共享数据3、线程B同步完后,线程A也同步,但是两个线程提交的是同一个值。*/count++;System.out.println(count);}}
}

测试类:

public class Demo07 {public static void main(String[] args) {Demo06 d = new Demo06();for (int i = 0; i < 100; i++) {new Thread(d).start(); // 9999}}
}

lock锁可以解决,但是效率比较低,因为每次要去判断锁、获得锁、释放锁

public class Demo01 {public static void main(String[] args) {Run runn = new Run();for (int i = 0; i < 100; i++) {new Thread(runn).start();}}
}
class Run implements Runnable {private volatile int count = 0;private Object lock = new Object();@Overridepublic void run() {for (int i = 0; i < 100; i++) {synchronized (lock) {count++;System.out.println("已经打印了  " + count + "  次");}}}
}
AtomicInteger方法:

构造方法:

方法名说明
public AtomicInteger()初始化一个默认值为0的原子型Integer
public AtomicInteger(int initialValue)初始化一个指定值的原子型Integer

成员方法:

方法名说明
int get()获取值
int getAndIncrement()以原子方式将当前值加1,注意,这里返回的是自增前的值
int incrementAndGet()以原子方式将当前值加1,注意,这里返回的是自增后的值
int addAndGet(int data)以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果
int getAndSet(int value)以原子方式设置为newValue的值,并返回旧值

: 。

    public static void main(String[] args) {// int get(): 获取值AtomicInteger ai1 = new AtomicInteger(10);System.out.println(ai1.get()); //10 // int getAndIncrement(): 以原子方式将当前值加1,注意,这里返回的是自增前的值。AtomicInteger ai2 = new AtomicInteger(10);System.out.println(ai2.getAndIncrement());//10System.out.println(ai2.get());//11// int incrementAndGet(): 以原子方式将当前值加1,注意,这里返回的是自增后的值。AtomicInteger ai3 = new AtomicInteger(10);System.out.println(ai3.incrementAndGet());//11// int addAndGet(int data): 以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。AtomicInteger ai4 = new AtomicInteger(10);System.out.println(ai4.addAndGet(1)); //11System.out.println(ai4.get()); //11// int getAndSet(int value): 先获得再设置新值。AtomicInteger ai5 = new AtomicInteger(10);System.out.println(ai5.getAndSet(1)); //10System.out.println(ai5);//1}

AtomicInteger解决共享数据问题:

public class Demo09 implements Runnable {AtomicInteger ac = new AtomicInteger(0);@Overridepublic void run() {for (int i = 0; i < 100; i++) {int count = ac.incrementAndGet();System.out.println(count);}}
}

incrementAndGet源码解析:

//先自增,然后获取自增后的结果
public final int incrementAndGet() {//+ 1 自增后的结果//this 就表示当前的atomicInteger(值)//1    自增一次return U.getAndAddInt(this, VALUE, 1) + 1;
}public final int getAndAddInt(Object o, long offset, int delta) {//v 旧值int v;//自旋的过程do {//不断的获取旧值v = getIntVolatile(o, offset);//如果这个方法的返回值为false,那么继续自旋//如果这个方法的返回值为true,那么自旋结束//o 表示的就是内存值//v 旧值//v + delta 修改后的值} while (!weakCompareAndSetInt(o, offset, v, v + delta));//作用:比较内存中的值,旧值是否相等,如果相等就把修改后的值写到内存中,返回true。表示修改成功。//                                 如果不相等,无法把修改后的值写到内存中,返回false。表示修改失败。//如果修改失败,那么继续自旋。return v;
}
synchronized和CAS的区别 :

相同点:

在多线程情况下,都可以保证共享数据的安全性。

不同点:

  • synchronized(悲观锁):总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每 次操作共享数据之前,都会上锁。

  • cas(乐观锁):是从乐观的角度出发,假设每次获取数据别人都不会修改,所以不会上锁。只不过在修改共享数据的时候,会检查一下,别人有没有修改过这个数据。如果别人修改过,那么我再次获取现在最新的值。如果别人没有修改过,那么我现在直接修改共享数据的值

Hashtable

Hashtable出现的原因 : 在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。
效率低的原因:因为底层是悲观锁,整个表都锁起来,那其他线程在外面等就会变的效率很低

    public static void main(String[] args) throws InterruptedException {Hashtable<String, String> hm = new Hashtable<>(100);Thread t1 = new Thread(() -> {for (int i = 0; i < 25; i++) {hm.put(i + "", i + "");}});Thread t2 = new Thread(() -> {for (int i = 25; i < 51; i++) {hm.put(i + "", i + "");}});t1.start();t2.start();System.out.println("----------------------------");//为了t1和t2能把数据全部添加完毕Thread.sleep(1000);//0-0 1-1 ..... 50- 50for (int i = 0; i < 51; i++) {System.out.println(hm.get(i + ""));}//0 1 2 3 .... 50}
ConcurrentHashMap:

ConcurrentHashMap出现的原因 : 在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。基于以上两个原因我们可以使用JDK1.5以后所提供的ConcurrentHashMap。

在这里插入图片描述

ConcurrentHashMap1.7和1.8区别:

JDK1.7
在这里插入图片描述

JDK1.8

  1. 如果使用空参构造ConcurrentHashMap对象,则什么事情都不做,在第一次添加元素的时候创建哈希表
  2. 计算当前元素应存入的索引
  3. 如果该索引位置为null,则利用cas算法,将本节点添加到数组中
  4. 如果该索引位置不为null,则利用volatile关键字获得当前位置最新结点地址,挂载它下面,变成链表
  5. 当链表的长度大于等于8时,自动转成红黑树
  6. 以链表或者红黑树头结点为锁对象,配合synchronized保证多线程操作集合时数据的安全性

在这里插入图片描述

    public static void main(String[] args) throws InterruptedException {ConcurrentHashMap<String, String> hm = new ConcurrentHashMap<>(100);Thread t1 = new Thread(() -> {for (int i = 0; i < 25; i++) {hm.put(i + "", i + "");}});Thread t2 = new Thread(() -> {for (int i = 25; i < 51; i++) {hm.put(i + "", i + "");}});t1.start();t2.start();System.out.println("----------------------------");//为了t1和t2能把数据全部添加完毕Thread.sleep(1000);//0-0 1-1 ..... 50- 50for (int i = 0; i < 51; i++) {System.out.println(hm.get(i + ""));}//0 1 2 3 .... 50}
CountDownLatch:

使用场景: 让某一条线程等待其他线程执行完毕之后再执行

方法解释
public CountDownLatch(int count)参数传递线程数,表示等待线程数量
public void await()让线程等待
public void countDown()当前线程执行完毕

线程一:

public class Thread1 extends Thread {private CountDownLatch countDownLatch;public Thread1(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}@Overridepublic void run() {// 让线程等待for (int i = 0; i < 10; i++) {System.out.println("线程一在执行第 " + i + " 次");}// 当前线程执行完毕,计数器-1,这时候线程还剩1countDownLatch.countDown();}
}

线程二:

public class Thread2 extends Thread {private CountDownLatch countDownLatch;public Thread2(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}@Overridepublic void run() {// 让线程等待for (int i = 0; i < 10; i++) {System.out.println("线程二在执行第 " + i + " 次");}// 当前线程执行完毕,计数器-1,这个时候计数器为0countDownLatch.countDown();}
}

父类线程:

public class FuThread extends Thread {private CountDownLatch countDownLatch;public FuThread(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}@Overridepublic void run() {//1.等待try {//当计数器变成0的时候,会自动唤醒这里等待的线程。countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("父类线程执行完毕");}
}

测试类:

public class Test {public static void main(String[] args) {//1.创建CountDownLatch的对象,需要传递给四个线程。//在底层就定义了一个计数器,此时计数器的值就是2CountDownLatch countDownLatch = new CountDownLatch(2);//2.创建三个线程对象并开启他们。FuThread motherThread = new FuThread(countDownLatch);motherThread.start();Thread1 t1 = new Thread1(countDownLatch);t1.setName("线程一");Thread2 t2 = new Thread2(countDownLatch);t2.setName("线程二");t1.start();t2.start();}
}
Semaphore:

使用场景 :

可以控制访问特定资源的线程数量。
比如有一个路口没有交警、没有红绿灯、会引发交通事故,可以做的和收费站一样发通行证、一次只能进来一辆车、或者两辆车、其他的等车想进来必须等这两个出去一个或者都出去、semaphore就是做这个,就是管理员的身份,也可以理解是有两个锁吧,执行完就释放锁,在执行就等待

实现步骤 :

  1. 需要有人管理这个通道
  2. 当有车进来了,发通行许可证
  3. 当车出去了,收回通行许可证
  4. 如果通行许可证发完了,那么其他车辆只能等着

线程类:

public class Thread1 implements Runnable{//1.获得管理员对象,private Semaphore semaphore = new Semaphore(2);@Overridepublic void run() {//2.获得通行证try {semaphore.acquire();//3.开始行驶System.out.println("获得了通行证开始行驶");Thread.sleep(2000);System.out.println("归还通行证");//4.归还通行证semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}
}

测试类:

public class Test {public static void main(String[] args) {Thread1  t= new Thread1();for (int i = 0; i < 5; i++) {new Thread(t).start();}}
}

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

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

相关文章

git revert

1. 我认为这是正确的做法&#xff1a; git fetch --all git reset --hard origin/mastergit fetch下载远程最新的&#xff0c;但不尝试&#xff0c;或重订任何东西。 然后&#xff0c;git resetmaster分支重置到你刚才牵强。 2. 试试这个&#xff1a; git reset --hard HEAD gi…

oracle 内存分配,Oracle调优修改10g,11g内存分配

先查看数据库是否使用spfile启动&#xff0c;如果不是的话&#xff0c;只需要在pfile中修改&#xff0c;然后重启数据库即可SQL> show parameter spfile;NAME TYPE VALUE------------------------------------ ----------- ------------------------------spfile string D:\…

在sql server数据库的一个表中如何查询共有多少字段

select a.* from sys.columns a,sys.tables bwhere a.object_id b.object_id and b.name 要查的表名转载于:https://www.cnblogs.com/firstdream/p/6899224.html

oracle自带的sql语言环境变量,Oracle技术网—SQL*Plus系统环境变量有哪些?如何修改?...

实现方法&#xff1a;show和set命令是两条用于维护SQL*Plus系统变量的命令SQL> show all--查看所有68个系统变量值SQL> show user--显示当前连接用户SQL> show error                --显示错误SQL> set heading off--禁止输出列标题&#xff0c;默…

第二个冲刺周期第二天

昨天实现了基本登录界面&#xff0c;今天对登录界面进行了进一步完善&#xff0c;遇到的问题就是如何把登录跟主界面连接起来&#xff0c;明天继续完善登录界面。转载于:https://www.cnblogs.com/1998lu/p/6926154.html

oracle 导出数据 utl,使用utl_file做选择性数据导出

在平时的数据导出中使用exp/expdp能够满足绝大部分的数据导出任务。如果有一些表的数据不多&#xff0c;但是查询条件要复杂一些&#xff0c;使用exp/expdp就很吃力了。或者在和外部系统的交互中&#xff0c;使用xml或者文本文件是一个很兼容的选择&#xff0c;这个时候使用exp…

oracle 10g express linux,在Ubuntu下安装Oracle Database 10g Express Edition

Oracle 10g有一款XE版&#xff0c;意为体验版&#xff0c;限制是不支持多CPU和数据库大小不能超过2G(还有其他的什么&#xff0c;不记得了&#xff0c;Oracle官方网站有写)。对于开发的时候调试一下&#xff0c;体验一下还是够用的。关键大小比较适中&#xff0c;安装包200多M。…

表单打印功能

表单打印的2种方式 一、支持不同的浏览器 1、表单打印功能调用window.print() 就可以打印了 2、如果只打印表单上的一部分样式&#xff0c;将不想打印的部分写在media print中&#xff0c;隐藏掉 <style>   media print{     .Noprint{       display:none; …

oracle硬盘亮黄灯,RH2288H V3服务器硬盘亮黄灯故障处理案例

原标题&#xff1a;RH2288H V3服务器硬盘亮黄灯故障处理案例本文广州诚本将分享RH2288H V3服务器硬盘亮黄灯故障处理案例&#xff0c;希望对大家的工作有所帮助。问题描述某客户新开局的项目&#xff0c;采购一批RH2288H V3的服务器&#xff0c;做RAID时发现其中一台服务器一块…

5.Lock接口及其实现ReentrantLock

jdk1.7.0_79 在java.util.concurrent.locks这个包中定义了和synchronized不一样的锁&#xff0c;重入锁——ReentrantLock&#xff0c;读写锁——ReadWriteLock等。在已经有了内置锁synchronized的情况下&#xff0c;为什么又出现了Lock显示锁呢&#xff1f;本文将以Lock作为Ja…

oracle近三个月内,在oracle中的前三个月SQL

我有以下的sql&#xff0c;它给了我最后一整个三个月的人处理的档案报告&#xff0c;但我想采用它&#xff0c;以便从前三个月获得这些&#xff0c;例如&#xff0c;当我运行现在我应该从2011年10月11日和12日以及2012年1月2日和3日的4月份获得档案。有人可以提出一个建议&…

什么是递归

概念&#xff1a; 递归指的是方法定义中调用方法本身的现象&#xff08;自己调自己&#xff09;把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算 递归注意事项&#xff1a; 递归一定要有出口。…

错误问题

1、系统出现如下错误&#xff1a;warning: LF will be replaced by CRLF 原因分析&#xff1a; CRLF -- Carriage-Return Line-Feed 回车换行 就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。 这两个ACSII字符不会在屏幕有任何输出&#xff0c;但在Windows中广泛使用来标…

oracle监听为blocked,关于“Instance +ASM1, status BLOCKED, ”

确实是可以的~只是需要配置一下~不过这个如果不操作ASM instacne的话没什么用Applies to:Oracle Net Services - Version: 10.1.0.4.0 to 10.2.0.4.0Information in this document applies to any platform.SymptomsChecking the listener status, ASM instance is shown as BL…

彻底学会IO流

概述&#xff1a; IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文件下载IO的数据传输&#xff0c;可以看做是一种数据的流动&#xff0c;按照流动的方向&#xff0c;已内存为参照物&#xff0c;进行读写操作IO可以保存到文件&#xff0c;其实就是内…

一些芯片资料

74hc14d u10 u11 u12 六反相触发器 74HC244 三态八缓冲器 u15 u13 uln2003afwg u16 74HC07 u17 L298N 步进电机驱动芯片 MOS管认知 转载于:https://www.cnblogs.com/legion/p/6908434.html

debian php安装pdo扩展,docker安装PHP扩展2020-05-25

示例&#xff1a;1、docker-php-ext-install pdo_mysql2、extensionphp_pdo_mysql.dll一、docker按照PHP扩展先删除原来的composer容器&#xff0c;重新执行以下命令&#xff1a;docker run -it --name composer -v E:\docker\nginx\www\YYXTServer:/app --privilegedtrue comp…

DP Intro - Tree DP Examples

因为上次比赛sb地把一道树形dp当费用流做了&#xff0c;受了点刺激&#xff0c;用一天时间稍微搞一下树形DP&#xff0c;今后再好好搞一下&#xff09; 基于背包原理的树形DP poj 1947 Rebuilding Roads 题意&#xff1a;给你一棵树,让你求最少剪掉多少条边可以剪出一棵点数为m…

强大的缓冲流

概述&#xff1a; 缓冲流的概述BufferedInputStream: 字节输入缓冲流BufferedOutputStream: 字节输出缓冲流四种方式复制字符缓冲流文本排序字符流读字符乱码问题InputStreamReader转换流读取字符数据OutputStreamWriter转换流写字符数据转换文件编码 1.缓冲流的概述&#xf…

linux驱动头文件查找目录,在Fedora 20中查找简单设备驱动程序的头文件

因此&#xff0c;我尝试按照简单的示例加载ORielly Linux设备驱动程序手册中的“ Hello World”设备驱动程序。问题是&#xff0c;由于某种原因&#xff0c;除非我在include语句中显式定义头文件的路径&#xff0c;否则它将无法正常工作。即我必须输入#include 而不只是#includ…