过火,abb的词语,decline-遇见枕头,睡眠新革命,我有遇见枕头,带来好睡眠

admin 2019-05-21 阅读:174

一、并发

Unable to create new native thread ……

问题1:Java中创立一个线程耗费多少内存?

每个线程有单独的栈内存,同享堆内存

问题2:一台机器能够创立多少线程?

CPU,内存,操作体系,JVM,运用服务器

咱们编写一段示例代码,来验证下线程池与非线程池的差异:

//线程池和非线程池的差异
public class ThreadPool {


public static int times = 100; // 100,1000,10000


public static ArrayBlockingQueue arrayWorkQueue = new ArrayBlockingQueue(1000);

public static ExecutorService threadPool = new ThreadPoolExecutor(5,// corePoolSize线程池中心中心线程数

10,

60,

TimeUnit.SECONDS,

arrayWorkQueue,

新的ThreadPoolExecutor.DiscardOldestPolicy()

);


public static void useThreadPool(){

Long start = System.currentTimeMillis();

for(int i = 0; i

threadPool.execute(new Runnable(){

public void run(){

的System.out.println( “说点什么吧......”);

}

});

}

threadPool.shutdown();

while(true){

if(threadPool.isTerminated()){

Long end = System.currentTimeMillis();

System.out.println(end - start);

打破;

}

}

}


public static void createNewThread(){

Long start = System.currentTimeMillis();

for(int i = 0; i


新线程() {

public void run(){

的System.out.println( “说点什么吧......”);

}

}。开端();

}

Long end = System.currentTimeMillis();

System.out.println(end - start);

}


public static void main(String args []){

createNewThread();

// useThreadPool();

}

}

发动不同数量的线程,然后比较线程池和非线程池的履行成果:

非线程池线程池

定论:不要new Thread(),选用线程池

非线程池的缺陷:

  • 每次创立功能耗费大
  • 无序,缺少办理。简单无约束创立线程,引起OOM和死机

1.1 运用线程池要注意的问题

防止死锁,请尽量运用CAS

咱们编写一个达观锁的完成示例:

公共类CASLock {

public static int money = 2000;


public static boolean add2(int oldm,int newm){

测验{

了Thread.sleep(2000);

} catch(InterruptedException e){

e.printStackTrace();

}

if(money == oldm){

money = money + newm;

回来true;

}

回来false;

}


public synchronized static void add1(int newm){

测验{

了Thread.sleep(3000);

} catch(InterruptedException e){

e.printStackTrace();

}

money = money + newm;

}


public static void add(int newm){

测验{

了Thread.sleep(3000);

} catch(InterruptedException e){

e.printStackTrace();

}

money = money + newm;

}


public static void main(String args[]) {
Thread one = new Thread() {
public void run() {
//add(5000)
while (true) {
if (add2(money, 5000)) {
break;
}
}
}
};
Thread two = new Thread() {
public void run() {
//add(7000)
while (true) {
if (add2(money, 7000)) {
break;
}
}
}
};
one.start();
two.start();
try {
one.join();
two.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(money);
}
}

运用ThreadLocal要注意

ThreadLocalMap运用ThreadLocal的弱引证作为key,假如一个ThreadLocal没有外部强引证来引证它,那么体系 GC 的时分,这个ThreadLocal必然会被收回,这样一来,ThreadLocalMap中就会呈现key为null的Entry,就没有办法拜访这些key为null的Entry的value,假如当时线程再迟迟不完毕的话,这些key为null的Entry的value就会一向存在一条强引证链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永久无法收回,形成内存走漏。

咱们编写一个ThreadLocalMap正确运用的示例:

//ThreadLocal运用实例
public class ThreadLocalApp {

public static final ThreadLocal threadLocal = new ThreadLocal();

public static void muti2() {
int i[] = (int[]) threadLocal.get();
i[1] = i[0] * 2;
threadLocal.set(i);
}

public static void muti3() {
int i[] = (int[]) threadLocal.get();
i[2] = i[1] * 3;
threadLocal.set(i);
}

public static void muti5() {
int i[] = (int[]) threadLocal.get();
i[3] = i[2] * 5;
threadLocal.set(i);
}

public static void main(String args[]) {
for (int i = 0; i < 5; i++) {
new Thread() {
public void run() {
int start = new Random().nextInt(10);
int end[] = {0, 0, 0, 0};
end[0] = start;
threadLocal.set(end);
ThreadLocalApp.muti2();
ThreadLocalApp.muti3();
ThreadLocalApp.muti5();
//int end = (int) threadLocal.get();
System.out.println(end[0] + " " + end[1] + " " + end[2] + " " + end[3]);
threadLocal.remove();
}
}.start();
}
}
}

1.2 线程交互—线程不安全形成的问题

经典的HashMap死循环形成CPU100%问题

咱们模仿一个HashMap死循环的示例:

//HashMap死循环示例
public class HashMapDeadLoop {

private HashMap hash = new HashMap();

public HashMapDeadLoop() {
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
hash.put(new Integer(i), i);
}
System.out.println("t1 over");
}
};

Thread t2 = new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
hash.put(new Integer(i), i);
}
System.out.println("t2 over");
}
};
t1.start();
t2.start();
}

public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new HashMapDeadLoop();
}
System.out.println("end");
}
}
https://coolshell.cn/articles/9606.html

HashMap死循环发作后,咱们能够在线程栈中观测到如下信息:

/HashMap死循环发作的线程栈
Thread-281" #291 prio=5 os_prio=31 tid=0x00007f9f5f8de000 nid=0x5a37 runnable [0x0000700006349000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap$TreeNode.split(HashMap.java:2134)
at java.util.HashMap.resize(HashMap.java:713)
at java.util.HashMap.putVal(HashMap.java:662)
at java.util.HashMap.put(HashMap.java:611)
at com.example.demo.HashMapDeadLoop$2.run(HashMapDeadLoop.java:26)

运用阻滞的死锁,Spring3.1的deadlock 问题

咱们模仿一个死锁的示例:

//死锁的示例
public class DeadLock {
public static Integer i1 = 2000;
public static Integer i2 = 3000;
public static synchronized Integer getI2() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return i2;
}
public static void main(String args[]) {
Thread one = new Thread() {
public void run() {
synchronized (i1) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (i2) {
System.out.println(i1 + i2);
}
}
}
};
one.start();
Thread two = new Thread() {
public void run() {
synchronized (i2) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (i1) {
System.out.println(i1 + i2);
}
}
}
};
two.start();
}
}

死锁发作后,咱们能够在线程栈中观测到如下信息:

//死锁时发作仓库
"Thread-1":
at com.example.demo.DeadLock$2.run(DeadLock.java:47)
- waiting to lock (a java.lang.Integer)
- locked (a java.lang.Integer)
"Thread-0":
at com.example.demo.DeadLock$1.run(DeadLock.java:31)
- waiting to lock (a java.lang.Integer)
- locked (a java.lang.Integer)
Found 1 deadlock.

1.3 根据JUC的优化示例

一个计数器的优化,咱们分别用Synchronized,ReentrantLock,Atomic三种不同的方法来完成一个计数器,领会其间的功能差异

//示例代码
public class SynchronizedTest {

public static int threadNum = 100;
public static int loopTimes = 10000000;

public static void userSyn() {
//线程数
Syn syn = new Syn();
Thread[] threads = new Thread[threadNum];
//记载运转时刻
long l = System.currentTimeMillis();
for (int i = 0; i < threadNum; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < loopTimes; j++) {
//syn.increaseLock();
syn.increase();
}
}
});
threads[i].start();
}
//等候一切线程完毕
try {
for (int i = 0; i < threadNum; i++)
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("userSyn" + "-" + syn + " : " + (System.currentTimeMillis() - l) + "ms");
}

public static void useRea() {
//线程数
Syn syn = new Syn();
Thread[] threads = new Thread[threadNum];
//记载运转时刻
long l = System.currentTimeMillis();
for (int i = 0; i < threadNum; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < loopTimes; j++) {
syn.increaseLock();
//syn.increase();
}
}
});
threads[i].start();
}
//等候一切线程完毕
try {
for (int i = 0; i < threadNum; i++)
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("userRea" + "-" + syn + " : " + (System.currentTimeMillis() - l) + "ms");
}
public static void useAto() {
//线程数
Thread[] threads = new Thread[threadNum];
//记载运转时刻
long l = System.currentTimeMillis();
for (int i = 0; i < threadNum; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < loopTimes; j++) {
Syn.ai.incrementAndGet();
}
}
});
threads[i].start();
}
//等候一切线程完毕
try {
for (int i = 0; i < threadNum; i++)
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("userAto" + "-" + Syn.ai + " : " + (System.currentTimeMillis() - l) + "ms");
}

public static void main(String[] args) {
SynchronizedTest.userSyn();
SynchronizedTest.useRea();
SynchronizedTest.useAto();
}
}

class Syn {
private int count = 0;
public final static AtomicInteger ai = new AtomicInteger(0);

private Lock lock = new ReentrantLock();

public synchronized void increase() {
count++;
}

public void increaseLock() {
lock.lock();
count++;
lock.unlock();
}

@Override
public String toString() {
return String.valueOf(count);
}
}

定论,在并发量高,循环次数多的状况,可重入锁的功率高于Synchronized,但终究Atomic功能最好。

二、通讯

2.1 数据库衔接池的高效问题

  • 必定要在finally中close衔接
  • 必定要在finally中release衔接

2.2 OIO/NIO/AIO

定论:我功能有苛刻要求下,尽量应该选用NIO的方法进行通讯。

2.3 TIME_WAIT(client),CLOSE_WAIT(server)问题

反响:经常性的恳求失利

获取衔接状况 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

  • TIME_WAIT:表明自动封闭,优化体系内核参数可。
  • CLOSE_WAIT:表明被迫封闭。
  • ESTABLISHED:表明正在通讯

解决方案:二阶段完成后强制封闭

2.4 串行衔接,耐久衔接(长衔接),管道化衔接

定论:

管道衔接的功能最优异,耐久化是在串行衔接的基础上减少了翻开/封闭衔接的时刻。

管道化衔接运用约束:

1、HTTP客户端无法承认耐久化(一般是服务器到服务器,非终端运用);

2、呼应信息次序有必要与恳求信息次序共同;

3、有必要支撑幂等操作才能够运用管道化衔接.

三、数据库操作

有必要要有索引(特别注意按时刻查询)

单条操作or批量操作

注:许多程序员在写代码的时分随意选用了单条操作的方法,但在功能要求前提下,要求选用批量操作方法。

四、JVM

4.1 CPU标高的一般处理过程

  • top查找出哪个进程耗费的cpu高
  • top –H –p查找出哪个线程耗费的cpu高
  • 记载耗费cpu最高的几个线程
  • printf %x 进行pid的进制转化
  • jstack记载进程的仓库信息
  • 找出耗费cpu最高的线程信息

4.2 内存标高(OOM)一般处理过程

  • jstat指令检查FGC发作的次数和耗费的时刻,次数越多,耗时越长阐明存在问题;
  • 接连检查jmap –heap 检查老生代的占用状况,改变越大阐明程序存在问题;
  • 运用接连的jmap –histo:live 指令导出文件,比对加载目标的差异,差异部分一般是发作问题的当地。

4.3 GC引起的单核标高

单个CPU占用率高,首先从GC查起。

4.4 常见SY标高

  • 线程上下文切换频频
  • 线程太多
  • 锁竞赛剧烈

4.5 Iowait标高

假如IO的CPU占用很高,排查涉及到IO的程序,比方把OIO改形成NIO。

4.6 颤动问题

原因:字节码转为机器码需求占用CPU时刻片,很多的CPU在履行字节码时,导致CPU长时间处于高位;

现象:“C2 CompilerThread1” daemon,“C2 CompilerThread0” daemon CPU占用率最高;

解决办法:确保编译线程的CPU占比。

作者:梁鑫

来历:宜信技术学院