<small id='r0vsb'></small> <noframes id='40kS'>

  • <tfoot id='og1cwMtdHj'></tfoot>

      <legend id='8uo73yY'><style id='9SdL'><dir id='wl2KxRq9z1'><q id='w45YS8P9an'></q></dir></style></legend>
      <i id='Mg0Cx'><tr id='ELamu2rAMQ'><dt id='Xi9r'><q id='C0w7VtlxS'><span id='ERSIP'><b id='lPez'><form id='MYWcaS7'><ins id='fo2RF'></ins><ul id='roGQh'></ul><sub id='fikLXMA5uD'></sub></form><legend id='DxfRknaBV'></legend><bdo id='6ZJm5cOM3'><pre id='2clOQxWwK'><center id='jQaKfJzqgW'></center></pre></bdo></b><th id='w7HE6'></th></span></q></dt></tr></i><div id='1RrvJU'><tfoot id='jhqeW'></tfoot><dl id='iyIJ5u'><fieldset id='mbU0'></fieldset></dl></div>

          <bdo id='k0rT5Bgi'></bdo><ul id='xje0TQ1c'></ul>

          1. <li id='N2IsWHXQm7'></li>
            登陆

            编写高性能的Java代码需求留意的4个问题

            admin 2019-05-21 281人围观 ,发现0个评论

            一、并发

            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);
            ThreadLocal编写高性能的Java代码需求留意的4个问题App.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 voi龙游天气d main(String args[]) {
            Thread one = new Thread() {
            public void run编写高性能的Java代码需求留意的4个问题() {
            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 编写高性能的Java代码需求留意的4个问题常见SY标高

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

            4.5 Iowait标高

            假如IO的CPU占用很高,排查涉及到IO的程序,比方把OIO改形成NIO。编写高性能的Java代码需求留意的4个问题

            4.6 颤动问题

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

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

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

            欢迎作业一到五年的Java工程师朋友们参加Java程序员开发: 721575865

            群内供给免费的Java架构学习材料(里边有高可用、高并发、高功能及分布式、Jvm功能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构材料)合理使用自己每一分每一秒的时刻来学习提高自己,不要再用"没有时刻“来粉饰自己思想上的懒散!趁年青,用力拼,给未来的自己一个告知!

            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP