当前位置: 首页 > wzjs >正文

湛江cms建站网络推广怎么做才有效

湛江cms建站,网络推广怎么做才有效,网站空间自己做,高端网站建设推荐万维科技从Java角度来看, 进程是运行时的程序,是计算机分配内存的最小单位。 线程是进程的一个执行单元,是cpu执行的最小单位。 进程 程序由指令和数据组成,指令的运行,数据的读写需要将指令加载至CPU,数据运行至…

从Java角度来看,
进程是运行时的程序,是计算机分配内存的最小单位。
线程是进程的一个执行单元,是cpu执行的最小单位。

进程

程序由指令和数据组成,指令的运行,数据的读写需要将指令加载至CPU,数据运行至内存。当一个程序被运行,从磁盘加载这个程序代码至内存,这时就开启了一个进程进程可以视为程序的一个实例。

线程

一个进程可以分为多个或一个线程。一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。Java中,线程作为最小调度单位,进程作为资源分配的最小单位。在windows中,进程是不活动的,只作为线程的容器。
并发(concurrent):同一时间应对多件事情的能力。(线程轮流使用CPU)
并行:同一时间动手做多件事情的能力。

如何创建线程?

  1. 继承Thread类,重写run()方法
  2. 实现Runnable接口,重写run方法,再创建Tread对象,去执行任务
    1和2的区别:继承Thread类后,由于java是单继承的,所以就不能再继承其他类了,实现Runnable接口的方式,还可以再继承其他类
  3. 实现Callable接口,重写call方法,创建Thread对象,去执行任务(call方法可以有返回值,可以抛出异常)
  4. 线程池创建

线程中常用的方法:run(),start(),join(),yield(),sleep(),wait(),notify()
线程的状态:新建,就绪,运行,阻塞,死亡
多线程安全问题:多线程共享资源操作
如何解决线程安全问题?加锁,排队,一个一个来并发的执行
在这里插入图片描述

如何加锁:

  1. synchronized关键字:同步对象(对多个对象来讲必须是同一个),用来记录有没有线程进入到同步代码块中。可以添加在代码块上,还可以添加在方法上。

synchronized(同步对象){
同步对象要求:多个线程对应的是同一个对象,用对象头中的一块区域来记录有没有进入到同步代码块中
}
synchronized修饰方法时,锁对象有两种:
1.修饰的是非静态方法,锁对象默认是this
2.修饰的是静态方法,锁对象是该类的Class对象

static synchronized void fun(){

}

  1. Lock接口,ReentrantLock类实现了Lock锁,它拥有了与synchronized相同的并发性和内存语义,在实现线程安全的控制中比较常用的是ReentrantLock,可以显式加锁,释放锁。
    ReentrantLock实现了Lock接口,所以可以成为Lock锁。

synchronized和ReentrantLock的区别:

  1. 实现原理不同: ReentrantLock是一种Java代码层面的控制实现,而synchronized是关键字,依靠的是底层编译后的指令实现。
  2. 加锁范围不同:ReentrantLock只能对某一代码块加锁,而synchronized可以对某一代码块或者方法加锁
  3. 加锁,释放锁方式不同: ReentrantLock需要我们手动释放锁,而synchronized是隐式自动释放锁(代码执行结束或出现异常,自动释放锁)。
线程死锁

死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。
死锁

public class DeadThread extends Thread {static Object objA = new Object();static Object objB = new Object();boolean flag;public DeadThread(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag) {synchronized (objA) {System.out.println("if objA");synchronized (objB) {System.out.println("if objB");}}} else {synchronized (objB) {System.out.println("else objB");synchronized (objA) {System.out.println("else objA");}}}}
}

设计时考虑清楚锁的顺序,尽量减少嵌套的加锁交互数量。


守护线程

线程分为用户线程和守护线程,守护线程为其他线程提供服务的,最大的特点是当系统其他用户线程结束后,守护线程会自动结束。jvm垃圾回收线程就是一个守护线程
daemonThread.setDaemon(true); //设置线程为守护线程,必须在线程启动前设置

线程通信

线程通信:指多个线程通过相互牵制,相互调度,即线程间的相互作用。
涉及三个方法:
.wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
.notify一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就会唤醒优先级最高的那个。
.notifyAll一旦执行此方法,就会唤醒所有被wait的线程。
注意:wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。

两个线程交替打印1-100数字:
public class PrintNumThread extends Thread {static int num = 1;static Object obj = new Object();@Overridepublic void run() {while (num <= 100) {synchronized (obj) {obj.notifyAll();System.out.println(Thread.currentThread().getName() + ":" + num);num++;try {if (num <= 100) {obj.wait();}} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

sleep()和wait()的区别:
sleep()是让线程阻塞指定时间,时间到了之后自己唤醒进入到就绪状态,不会释放同步锁。是Thread类中的方法.
wait()让线程进入等待(阻塞),不会自己唤醒,必须通过notify/notifyAll来唤醒。是Object类中的方法
共同点:都可以让线程进入阻塞状态。

生产者消费者问题
public class Counter {int num = 0;public synchronized void add() {if (num == 0) {this.notify();num = 1;System.out.println("生产者生产了一个资源:" + num);} else {try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}public synchronized void sub() {if(num==0){try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else{this.notify();num = 0;System.out.println("消费者消费了一个资源:" + num);}}
}
-------------------------------------------------------
public class Producter extends Thread{Counter counter;public Producter(Counter counter) {this.counter = counter;}@Overridepublic void run(){while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}counter.add();}}
}
---------------------------------------------------
public class Consumer extends Thread{Counter counter;public Consumer(Counter counter) {this.counter = counter;}@Overridepublic void run(){while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}counter.sub();}}
}
---------------------------------------------------------
public class Test {public static void main(String[] args) {Counter counter=new Counter();Consumer c = new Consumer(counter);Producter p = new Producter(counter);c.start();p.start();}
}
新增创建线程方式

实现Callable接口与使用Runnable相比,Callable功能更强大些

  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,获取返回结果
public class Test {public static void main(String[] args) {SumTask sumTask = new SumTask();FutureTask<Integer> futureTask = new FutureTask(sumTask);Thread thread = new Thread(futureTask);thread.start();Integer integer = null;try {integer = futureTask.get();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}System.out.println(integer);}
}
---------------------------------------
public class SumTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum=0;for(int i=0;i<=10;i++){sum+=i;}return sum;}
}

线程进阶

多线程优点:提高线程响应速度,可以多个线程各自完成自己的工作,提高硬件设备的利用率。
缺点:在多个线程同时访问共享数据时,可能出现资源争夺问题。线程中的重点就是解决线程安全问题。(接下来解决的重点问题)

并发执行:是在一个时间段内依次轮流执行(微观串行,宏观并行
并行执行:是真正意义上的同一时间点上一起执行
多线程场景下,对共享资源的访问应该是并发的执行
平常所说的高并发,此处指的并发,就是很多用户一起访问
并发编程核心问题:不可见性、乱序性、非原子性

不可见性

一个线程对共享变量的修改,另一个线程不能立刻看到,我们称为不可见性。
由于想让程序响应处理速度更快,java内存模型设计有主内存和工作内存(线程使用的内寸),线程中不能直接对主内存中的数据进行操作,必须将主内存数据加载到工作内存(本地内存),这样在多核CPU下,就会产生不可见性。
我们的目标要做到可见性

volatile关键字(解决不可见性乱序性

一旦一个共享变量被volatile关键字修饰以后,

  1. 保证了不同线程对这个变量操作的可见性,即一个线程修改了某个变量的值,这个新值对其他线程来说立即可见;(可见性)
  2. 禁止进行指令重排序;(有序性)
  3. volatile不能保证对变量操作的原子性。(非原子性)
volatile的底层实现原理(待更新...
JMM(待更新...
乱序性

指令在执行过程中,为了优化性能,有的时候会改变程序中语句的先后顺序。
这种改变可能会影响程序整个运行结果
CPU的读等待同时指令执行是CPU乱序执行的根源。读指令的同时可以执行不影响其他指令。

非原子性

线程切换带来的非原子性问题。
原子的意思代表不可分。一个或多个操作在CPU执行的过程中不被中断的特性,我们称为原子性。原子性是拒绝多线程交叉操作的,不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程对它进行操作。
CPU能保证原子操作是CPU指令级别的,而不是高级语言的操作符。线程导致了原子性问题。

如何保证原子性(加锁、原子变量)

同一时刻只有一个线程执行,我们称为互斥。如果我们能够保证对共享变量的修改是互斥的,那么就能保证原子性了。

  • 加锁是一种阻塞式方式实现
  • 原子变量是一种非阻塞式方式实现
加锁

互斥的,A线程执行时加锁,此时其他线程就不能再执行了

原子变量

在java.util.concurrent包下面提供了一些类,可以在不加锁的情况下实现++操作的原子性。这些类称为原子类AtomicInteger。
原子类内部实现是volatile+CAS机制
原子类内部实现使用了不加锁的CAS机制

CAS(compare-and-swap)算法:比较并交换

CAS算法:是一种不加锁的实现(乐观锁)机制,采用自旋的思想,当一个线程进行++操作时,可先从内存中取出共享变量,记录一个预估值,然后在工作内存中修改共享变量,当将修改的变量写回主内存前,要判断预估值是否与主内存中的值一致,如果一致说明没有其他线程修改过。如果不一致,说明其他线程修改过,需要重新获取主内存共享变量,重复之前的操作。
CAS缺点:CAS使用自旋的方式,由于该锁会不断循环判断,因此不会类似synchronized线程阻塞导致线程切换。但是不断的自旋,会导致CPU的消耗过高。

原子类适合在低并发情况使用

会产生ABA问题(A->B->A):一个线程获取内存值为A,当线程修改后要写内存时,但已经有其他线程改变了内存值,又有线程将内存值改回到与当前预估值相同的值。
如何解决ABA问题?使用有版本号的原子类

Java中的锁分类(synchronized、ReentrantLock、ReentrantReadWriteLock)

Java中有很多锁的名词,这些并不全指锁,有的指锁的特性,有的指锁的设计,有的指锁的状态

乐观锁/悲观锁
乐观锁

乐观锁认为对于同一个数据的并发操作,是不会发生修改的。乐观锁其实就是不加锁。并发修改时,进行比较,满足条件进行更新,否则再次比较。例如原子类。

悲观锁(例如synchronized)

悲观锁认为不加锁的是肯定会出问题的,使用java中提供的各种锁实现加锁。悲观锁适合写操作比较多的情况,乐观锁适合读多写少的情况。

可重入锁

当一个线程进入到一个同步方法中,然后在此方法中要调用另一个同步方法,而且两个方法共用同一把锁,此时线程是可以进入到另一个同步方法中的。

读写锁

ReentrantReadWriteLock可以实现读锁写锁,读写可以使用一个锁实现,都是读的时候,多个线程可以共享这把锁(可以同时进入),一旦有写的操作,那么就要一个一个操作

读读共享
读写互斥
写写互斥
加读锁是防止在另外的线程在此时写入数据,防止读取脏数据

分段锁

JDK8之后去除了真正的分段锁,现在的分段锁不是锁,而是一种实现思想
分段锁并非一种实际的锁,而是一种思想。用于将数据分段,并在每个分段上都会单独加锁,把锁进一步细粒度化,以提高并发效率。
例如ConcurrentHashMap,没有给方法加锁,而是用hash表中第一个节点当作锁,这样就可以有多把锁,提高并发效率。

自旋锁

也不是锁,是获取锁的方式。例如:

  • 原子类,需要改变内存中的变量,需要不断尝试
  • synchronized加锁,其他线程不断尝试获取锁
共享锁/独占锁
共享锁

多个线程可以共享的一把锁,读写锁中的读锁,都是读操作时多个线程共用一把锁

独占锁

synchronizedReentratLock,互斥的,读写锁中的写锁

公平锁/非公平锁
公平锁

公平锁(Fair Lock)是按照请求锁的顺序分配,拥有稳定获取锁的机会。

非公平锁

非公平锁(Nonfair Lock)是指不按照请求锁的顺序分配,不一定拥有获取锁的机会。
synchronized是一种非公平锁
ReentrantLock默认非公平锁,但是底层可以通过AQS来实现线程调度,所以可以使其变成公平锁。

偏向锁/轻量级锁/重量级锁(锁的状态)

在这里插入图片描述
是针对synchronized锁的状态:

  1. 无锁状态:没有任何线程进入同步代码块
  2. 偏向锁状态:当前只有一个线程访问,在对象头Mark Word中记录线程id,下次此线程访问可直接获取锁
  3. 轻量级锁状态:锁状态为偏向锁,此时继续有线程访问,升级为轻量级锁,会让线程以自旋方式获取锁,线程不会阻塞
  4. 重量级锁状态:锁状态为轻量级锁,线程自旋获取锁的次数到达一定数量时,锁的状态升级为重量级锁,会让自旋次数多的线程进入到阻塞状态,因为访问量大,线程都自旋获得锁,CPU消耗大

锁的状态是通过对象监视器在对象头中的字段来表明的。四种状态会随着竞争的情况逐渐升级。
这四种状态都不是Java语言中的锁,而是JVM为了提高锁的获取与释放效率而做的优化(使用synchronized时)

偏向锁

偏向锁是指一段同步代码块一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价。

轻量级锁

轻量级锁是指当锁是偏向锁的时候,此时又有一个线程访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋形式尝试获取锁,不会阻塞,提高性能。

重量级锁

重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。在高并发情况下,出现大量线程自旋获得锁,对CPU销毁较大,升级为重量级锁后,获取不到锁的线程将阻塞,等待操作系统的调度。

以上状态设计是Java为了优化synchronized锁

对象结构

对象结构
MarkWord

synchronized锁的实现(通过底层指令控制实现)

在这里插入图片描述
在这里插入图片描述
synchronized修饰方法:底层指令会添加ACC_SYNCHRONIZED,进入方法时使用monitorenter检测,执行完毕使用monitorexit释放锁
synchronized修饰代码块:进入代码块时使用monitorenter检测,执行完毕使用monitorexit释放锁

ReentrantLock锁实现(默认非公平锁)

源码实现:

public class ReentrantLock implements Lock, java.io.Serializable {abstract static class Sync extends AbstractQueuedSynchronizer {...}static final class NonfairSync extends Sync {final void lock() {if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread());//先尝试获取锁,修改锁的状态。成功则设置为独占线程else acquire(1);//否则走正常流程}}static final class FairSync extends Sync {final void lock() {acquire(1);//走正常流程获取锁,如果当前锁状态为0,则改为1//如果状态为1,把线程放入到队列}}public ReentrantLock() {sync = new NonfairSync();//无参构造方法//默认使用非公平锁}public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();//有参构造方法}}

公平锁和非公平锁继承ReentrantLock内部静态类Sync。
Sync继承AbstractQueuedSynchronizer抽象同步队列。
ReentrantLock 是 Java 并发包 (java.util.concurrent.locks) 中的一个可重入互斥锁实现类,它提供了与 synchronized 关键字相似的功能,但具有更灵活的特性。

主要特点:

  1. 可重入性:同一个线程可以多次获取同一个锁,内部通过计数器跟踪重入次数。
  2. 公平性选择:
  • 非公平锁(默认):不保证线程获取锁的顺序,性能较高但可能导致线程饥饿
  • 公平锁:按照线程请求锁的顺序分配锁,减少饥饿但性能较低
  1. 可中断:提供了可中断的获取锁方法
  2. 超时尝试:可以尝试在指定时间内获取锁

使用示例:

ReentrantLock lock = new ReentrantLock();
// ...
lock.lock();
try {// 临界区代码
} finally {lock.unlock();
}
AQS(AbstractQueuedSynchronizer)抽象同步队列

AQS:是一个底层具体的同步实现者,很多同步的类底层都用到了AQS。
AbstractQueuedSynchronizer类中有一个int类型的state变量记录锁的状态。这个类在java.util.concurrent包下面
内部类

volatile int state;//标记有没有线程在访问共享资源
protected final int getState(){return state;
}
static final class Node{volatile  Node prev;volatile Node next;volatile Thread thred;
}
protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

JUC常用类

ConcurrentHashMap(java.util.concurrent包中)

存储键值对,双列集合。键不可重复,值可以重复
HashMap: hashCode();equals(); 哈希冲突
结构:哈希表,默认长度为16,数组长度-1 & hash值
负载因子0.75 扩容为原来2倍
链表 8 哈希表长度大于等于64转红黑树
红黑树 线程不安全。单线程情况下可以使用
HashTable:线程安全的,方法加了synchronized关键字,读也加了锁。读写互斥,并发访问效率低,适合并发量低的情况下使用
线程安全的,采用CAS+synchronized保证线程安全。
put时,先用key计算hash值,再计算位置。如果是当前位置的第一个元素,采用CAS机制尝试放入。如果当前位置已经有了元素,那么使用第一个元素作为锁对象,使用synchronized加锁。这样就会降低锁的粒度,可以同时有多个方法进入到put的方法中操作,提高并发效率。
如果有多个线程对同一位置操作,那么就必须一个一个操作。
ConcurrentHashMap不支持存储为null的键和值
HashTable不支持存储为null的键和值

原因:为了消除歧义。由于ConcurrentHashMap和HashTable都是支持并发的,当通过get(K,V)获取对应value时,如果获取到的为null,无法判断当前value为null还是这个key从未做过映射

concurrentHashMap类putval方法源码:

final V putVal(K key, V value, boolean onlyIfAbsent) {//首先检查 key 或 value 是否为 null,如果是则直接抛出 NullPointerException(ConcurrentHashMap 不允许空键或空值)if (key == null || value == null) throw new NullPointerException();//通过 spread() 方法对键的哈希码进行二次散列,目的是减少哈希冲突int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {//自旋插入逻辑(无限循环直到成功)Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)//1.情况一:表未初始化tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//2.情况二:目标桶为空if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))// 通过 (n-1) & hash 计算桶位置break; // 使用 CAS原子操作插入新节点,避免加锁}else if ((fh = f.hash) == MOVED)//3.情况三:正在扩容tab = helpTransfer(tab, f);//协助扩容else {//4.情况四:桶不为空(需加锁)//对桶头节点加 synchronized 锁
//处理两种子情况:链表或红黑树V oldVal = null;synchronized (f) {// 锁定桶头节点if (tabAt(tab, i) == f) {// 再次验证防止被修改if (fh >= 0) {// 普通链表节点binCount = 1;// 遍历链表查找key,找到则更新,未找到则追加for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin) { // 红黑树节点// 通过树节点方式插入Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)// 超过树化阈值treeifyBin(tab, i); // 可能转为红黑树if (oldVal != null)return oldVal;// 如果是更新操作返回旧值break;}}}addCount(1L, binCount);// 原子更新元素计数器return null;
}

设计亮点:
分段锁优化:只在操作具体桶时加锁,不同桶可并行操作
CAS无锁插入:空桶插入使用CAS避免锁开销
协助扩容:遇到正在扩容的桶会协助完成迁移
锁粒度细化:只锁单个桶头节点而非整个表

CopyOnWriteArrayList
  • ArrayList:单列集合 底层是数组实现 可存储重复元素 有序存储
    可以自动扩容 默认长度为10 扩容为原来的1.5倍
    线程不安全
  • Vector:单列集合 底层是数组实现 可存储重复元素 有序存储
    可以自动扩容 默认长度为10 扩容为原来的2倍
    线程安全锁添加到方法上的,并发效率低

读取数据时也进行加锁是一种资源的浪费,读是不改变数据的。
CopyOnWriteArrayList类中所有可变操作都是通过创建底层数组的新副本来实现的。添加、修改(写)方法加锁(使用ReentrantLock加锁),get(读)方法不加锁,提高读的效率。适合读多写少情况。

CopyOnWriteArraySet

CopyOnWriteArraySet实现基于CopyOnWriteArrayList,线程安全,不能存储重复数据。

CountDownLatch

CountDownLatch允许一个线程等待其他线程各自执行完毕后再执行。底层是通过AQS(同步队列)完成。创建CountDownLatch对象时指定一个初始值是线程的数量。每当一个线程执行完毕,AQS内部的state就-1,当state值为0,所有线程执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch=new CountDownLatch(1000);//初始化计数器为 1000,表示需要等待 1000 个事件完成for(int i=0;i<1000;i++){new Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("1");countDownLatch.countDown();//调用 countDown() 减少计数器}).start();}countDownLatch.await();//主线程会阻塞在这里,直到计数器减到 0System.out.println("_______________main_______________");//当所有 1000 个线程都执行完后,主线程继续执行}
}

典型应用场景

  • 启动服务时等待所有组件初始化完成
  • 并行计算时等待所有子任务完成
  • 测试用例中协调多个并发操作

池(容器/集合/ArrayList)

每次连接数据库都要创建一个连接对象,用完之后就销毁了,频繁创建销毁会占用一定的开销。
提出 的概念,可以创建一定数量的连接对象放在池子中,有连接到来时,从池子中获得一个连接对象使用,用完之后不销毁,还回到池子中即可。减少创建、销毁开销。
例如:字符串常量池、数据库连接池、线程池

数据库连接池
import com.alibaba.druid.pool.DruidDataSource;import java.sql.Connection;
import java.sql.SQLException;public class DruidUtil {static   DruidDataSource dataSource;static {dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/ssm_db?serverTimezone=Asia/Shanghai");dataSource.setUsername("root");dataSource.setPassword("xxxxxxxx");dataSource.setInitialSize(10);dataSource.setMaxActive(20);}public static Connection getConnection() throws SQLException {return dataSource.getConnection();}public static void close(Connection connection) throws SQLException {connection.close();}
}
线程池
http://www.dtcms.com/wzjs/80087.html

相关文章:

  • 应该选用哪种口罩公司seo是指什么意思
  • 搬瓦工可以做网站吗推广
  • 做投资理财网站市场调研报告怎么写
  • 青岛哪个网站建设公司价格低还能好一些永久免费建个人网站
  • 朝阳市营商环境建设监督局网站郑州seo顾问热狗
  • 上海高端网站开发公今日郑州头条最新新闻
  • 张家港网站建设模板色盲测试
  • 衢州 网站建设网站自助建站系统
  • wordpress 多语言站点哈尔滨百度推广公司
  • 管理网站建设源代码程序企业建站平台
  • 电影网站建设java深圳sem优化
  • 合肥建设局网站上海百度分公司电话
  • 做购物网站费用帮我搜一下长沙做网络销售
  • 参考消息官方网站阅读西安seo推广公司
  • 新手做网站怎么上传系统济南市最新消息
  • 自己做网站什么网站比较好电商网站销售数据分析
  • 河北共产党员网站两学一做免费建立个人网站凡科
  • 深圳 网站设计公司排名搜索引擎优化的方法
  • 网站导航栏全屏怎么做的搜索引擎优化
  • 网站建设需求问卷千锋教育培训收费一览表
  • 网站管理员工作总结广告买卖网
  • 网站建设的具体实施方案郑州seo询搜点网络效果佳
  • 山东省建设执业官方网站搜狗网页版入口
  • 网站界面设计要素广告公司推广
  • 单页产品销售网站如何做推广百度不让访问危险网站怎么办
  • 有哪些网站可以接单做效果图重庆网站排名推广
  • 网站404设置今日头条网页版入口
  • 江西手机版建站系统开发百度高级搜索入口
  • 吉林省电力建设总公司网站seo综合查询国产
  • funpinpin建站平台外贸推广哪个公司好