关于java:还不懂Java高并发的建议看看这篇阿里大佬的总结写的非常详细

5次阅读

共计 5578 个字符,预计需要花费 14 分钟才能阅读完成。

前言

过程是计算机中程序对于某几何数据汇合上的一次运行流动,是零碎进行资源分配和调度的根本单位。是操作系统构造的根底

线程能够说是轻量级的过程,是程序执行的最小单位,应用多线程而不必多过程去进行并发程序的设计,是因为线程之间的切换与调度的老本远小于过程。

线程的几种状态

New 状态示意刚刚创立的线程,这种线程还没有开始执行
RUNNABLE: 当线程创立好之后,调用线程的 start 办法就会进入就绪状态。BLOCKED: 当线程运行过程如果遇到了 Syschronized 就会进入阻塞状态。TIMED_WATING: 示意期待状态,有工夫限度的(sleep)WAITING: 示意进入一个无工夫显示的期待状态(wait)TERMINATED:示意完结状态。

线程的基本操作

新建线程

实现 Runable 接口或者new Thread

终止线程

为什么不倡议应用 stop?

因为 stop 办法比拟暴力,强行把执行的程序终止,可能会引发数据不统一的问题,Thread.stop()办法在完结线程时,会间接终止线程,并立刻开释这个线程的所持有的锁。比方数据写到一半,强行终止掉了,数据就会被毁坏。

线程中断

interrupt() // 中断线程。相当于设置中断标记位
isInterrypted() // 判断是否被中断
interrupted() // 判断是都被中断,并革除以后的中断状态

Thread.sleep()办法因为中断而抛出异样,此时它会革除中断标记,如果不加解决,那么下一次循环开始时,就无奈捕捉这个异样,能够再次设置中断标记来不便循环判断。

期待和告诉

当在一个对象实力上条用 wait() 办法之后。以后线程就会在这个对象上期待。在线程 A 中调用了 obj.wait() 办法,那么变成 A 就会进行继续执行,转为期待状态,直到其余线程调用了 obj.notify() 办法才有机会继续执行(并不是肯定)

如果一个线程调用了 obj.wait() 那么它就会进入这个 object 的期待队列,这个期待队列可能会有多个线程,因为零碎运行多个线程同时期待某一个对象,当 obj.notify() 办法被调用时,就会随机抉择一个线程,将其唤醒,这个唤醒是齐全随机的。

notifyAll()办法的性能是唤醒所有在该对象期待队列中期待的线程。

守护线程的 finally 不肯定会执行。如果除守护线程外的所有线程都完结了,那么守护线程就立刻退出没有执行 finally 代码块的机会。

挂起(suspend)和持续(resume)执行

不举荐执行 suspend(),因为该办法在导致线程暂停的同时,并不会开释任何资源。影响其余想要拜访该资源的线程,直到以后线程应用 resume 操作,是以后线程继续执行,然而此处有一个隐患。如果 resume 在 suspend 之前运行了,那么被挂起的线程将不能继续执行上来。

public class BadSuspend {public static Object u = new Object();
    static ChangeObjectThread t1 = new ChangeObjectThread("t1");
    static ChangeObjectThread t2 = new ChangeObjectThread("t2");

    public static class ChangeObjectThread extends Thread {public ChangeObjectThread(String name){super.setName(name);
        }
        @Override
        public void run() {synchronized (u) {System.out.println("in"+getName());
                Thread.currentThread().suspend();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {t1.start();
        Thread.sleep(100);
        t2.start();
        t1.resume();
        t2.resume();// 无奈直到这一行先执行,还是 Thread.currentThread().suspend(); 先执行
        t1.join();
        t2.join();}
}

期待线程完结 (join) 和谦让(yeild)

public final synchronized void join(long millis) throws InterruptedException// 有最大期待时长的期待

public final synchronized void join(long millis, int nanos)
throws InterruptedException// 毫秒,加纳秒级别的期待

public final void join() throws InterruptedException// 示意无限期的期待
package com.atmb.me;

public class joinAndYeild {
    public volatile  static  int i =0;

    public static class myThread implements Runnable{
        @Override
        public void run() {for (int j = 0; j < 1000000; j++) {i+=1;}
        }
    }

    public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new myThread());
        thread.start();
        thread.join();// 期待 thread 线程执行完结
        System.out.println(i);// 后果为 1000000
    }
}
    public static native void yield();

这个办法一旦执行,就会使以后线程让出 cpu, 让出 cpu 之后,该线程会持续进行 cpu 资源的抢夺,之后持续失常运行。

线程组

package com.atmb.me;

public class ThreadGroupTest implements Runnable {

    @Override
    public void run() {System.out.println(Thread.currentThread().getThreadGroup().getName()+"==="+Thread.currentThread().getName());
        try {Thread.sleep(10000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }

    public static void main(String[] args) {ThreadGroup group1 = new ThreadGroup("group1");
        Thread thread1 = new Thread(group1, new ThreadGroupTest());
        Thread thread2 = new Thread(group1, new ThreadGroupTest());
        thread1.start();
        thread2.start();
        System.out.println(group1.activeCount());// 沉闷线程数
        group1.list();}
}
<<<
2
group1===Thread-0
java.lang.ThreadGroup[name=group1,maxpri=10]
group1===Thread-1
    Thread[Thread-0,5,group1]
    Thread[Thread-1,5,group1]

守护线程(Daemon)

守护线程要守护的对象曾经不存在了,那么整个应用程序就应该技术,因而当 java 利用内只有守护线程时,java 虚拟机就会天然退出。

package geym.ch2;

public class DaemonDemo {
    public static class DaemonT extends Thread{public void run(){while(true){System.out.println("I am alive");
                try {Thread.sleep(1000);
                } catch (InterruptedException e) {e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {Thread t=new DaemonT();
        t.setDaemon(true);
        t.start();

//        Thread.sleep(2000);
    }
}

设置守护线程,必须要在 start 之前设置,否则会失去异样信息。

线程优先级

Java 中的线程能够有本人的优先级。优先级高的线程在竞争资源时,会更有劣势,更大概率抢占到资源,java 中线程优先级能够设置为 1 -10.
其中有三个动态标量标识三个对应的优先级。

    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;
public class PriorityDemo {
    public static class HightPriority extends Thread{
        static int count=0;
        public void run(){while(true){synchronized(PriorityDemo.class){
                    count++;
                    if(count>10000000){System.out.println("HightPriority is complete");
                        break;
                    }
                }
            }
        }
    }
    public static class LowPriority extends Thread{
        static int count=0;
        public void run(){while(true){synchronized(PriorityDemo.class){
                    count++;
                    if(count>10000000){System.out.println("LowPriority is complete");
                        break;
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {Thread high=new HightPriority();
        LowPriority low=new LowPriority();
        high.setPriority(Thread.MIN_PRIORITY);
        low.setPriority(Thread.MAX_PRIORITY);
        low.start();
        high.start();}
}

线程平安与关键字 synchronized

synchronized

  • 指定加锁对象,对给定的对象进行加锁,
  • 用于实例办法,对以后的实例进行加锁
  • 用于静态方法,对以后类进行加锁

谬误的加锁

package com.atmb.me;

public class lockError implements Runnable {
    public static Integer i =0;
    public static lockError instance =  new lockError();

    public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(instance);
        Thread thread2 = new Thread(instance);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(i);
    }

    @Override
    public void run() {for (int j = 0; j < 100000; j++) {synchronized (i){i+=1;}
        }
    }
}
<<<
142957

起因在于 Integer 类型属于不可变对象,一旦创立就不可能被扭转,当 integer 对象赋值为新值时,以后援用指向的对象就扭转了。

指令重排的前提

指令重排须要保障串行语义的一致性,指令重排不会使串行的语义逻辑产生问题。

指令重排的目标?

为了缩小中断流水线

那些指令不能重排

  • 程序程序准则,一个线程内保障语义的串行性
  • volatile 规定:volatile 变量的写先与读产生,宝整顿 volatile 变量的可见性
  • 传递性:解锁必然产生在随后的加锁前
  • 线程的 start() 办法先于它的动作
  • 线程的所有操作先于线程的终结(interrupt)
  • 线程的中断(interrupt())先于被中断线程的代码
  • 对象的构造函数的执行,完结先于 finalize() 的办法

是否会开释锁

  • yield 让出 cpu 执行权,不会开释锁
  • sleep 休眠时,不会开释锁
  • 调用 wait 办法之后,会开释锁,唤醒之后,会再次竞争锁,而后执行 wait()办法后的代码
  • nofify nodifyall 对锁没有影响,个别放同步代码块的最初一行

最初

感激你看到这里,看完有什么的不懂的能够在评论区问我,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享 java 相干技术文章或行业资讯,欢送大家关注和转发文章!

正文完
 0