线程优先级

public static void main(String[] args){
    Thread thread = new Thread();
    thread.start();
    int ui_proi = Process.getThreadPriority(0)
    int th_proi = thread.getPriority();
    //输出成果
    ui_proi = 5
    th_proi = 5
}

1.线程的优先级是具有承继性的,在某个线程中创立的线程会承继线程的优先级。例如咱们在UI线程中创立了线程,则线程优先级和UI线程优先级相同,相等的和UI线程抢占CPU时刻资源。

2.JDKAPI 中约束了新设置的线程优先级有必要为[1~10], 优先级priority越高,获取CPU时刻片段的概率越高。

java.lang.Thread.setPriority(int newPriority)

3.Android API 能够为线程设置愈加精密的优先级(-20~19)优先级priority的值越低,获取CPU时刻片的概率越高。

android.os.Process.setThreadPriority(int newPriority)

线程的状况

NEW 初始状况,线程被新建,还没调用start办法

RUNNABLE 运转状况,把“运转中”和“就绪”统称为运转状况

BLOCKED 堵塞状况,表明线程堵塞于锁

WAITING 等候状况,需求其他线程告诉唤醒

TIME_WAITING 超时等候状况,表明能够在指定的时刻超时后自行返回

TERRMINATED 终止状况,表明当前线程已履行完毕

下图表明线程各种状况间的切换

Android常用多线程解析(二)线程安全

wait 线程进入等候

wait关键字能使线程进入等候,开释线程锁

/**================================================================
 * wait关键字
 * wait关键字能使线程进入等候,开释线程锁,抱负状况下thread1应该先履行,履行进入wait办法后开释线程锁,thread得以继续向下履行,唤醒线程1继续履行
 * 日志应该为
 * RUN1---start
 * RUN2---start
 * RUN1---end
 * RUN2---end
 * 可是无法确定线程1或线程2谁先履行,若线程2 先履行,线程1履行wait办法后将进入等候且无人唤醒,所以需求加原子变量操控
 * 实践日志
 *
 D/ThreadTestForJava: RUN2---start1644565101644
 D/ThreadTestForJava: RUN2---end1644565101644
 D/ThreadTestForJava: RUN1---start1644565101645
 * ================================================================
 */
Object obj = new Object();
class Runable1 implements Runnable{
    @Override
    public void run() {
        Log.d(TAG, "RUN1---start" + System.currentTimeMillis());
        synchronized (obj){
            try {
                if(isWait){
                    obj.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.d(TAG, "RUN1---end" + System.currentTimeMillis());
    }
}
class Runable2 implements Runnable{
    @Override
    public void run() {
        Log.d(TAG, "RUN2---start" + System.currentTimeMillis());
        synchronized (obj){
            isWait = false;
            obj.notify();
        }
        Log.d(TAG, "RUN2---end" + System.currentTimeMillis());
    }
}
public void waitTest(){
    Thread thread1 = new Thread(new Runable1());
    Thread thread2 = new Thread(new Runable2());
    thread1.start();
    thread2.start();
}
join关键字

join关键字的效果是等候目标线程履行完后再履行此线程

/**
 * ===============================================================================
 * join关键字
 * 等候目标线程履行完后在履行此线程
 * 正常状况先,runable4应该先履行完,然后runable3会等候10秒后才干走完,在runable4中调用join办法,runable4将会等候runable3走完才继续履行
 * 未参加join
 * D/ThreadTestForJava: RUN4---start1644566194613
 * D/ThreadTestForJava: RUN4---end1644566194614
 * D/ThreadTestForJava: RUN3---start1644566194614
 * D/ThreadTestForJava: RUN3---end1644566204616
 * 参加join
 * D/ThreadTestForJava: RUN3---start1644566395452
 * D/ThreadTestForJava: RUN4---start1644566395453
 * D/ThreadTestForJava: RUN3---end1644566405455
 * D/ThreadTestForJava: RUN4---end1644566405458
 * ===============================================================================
 */
Thread thread3 = new Thread(new Runable3());
Thread thread4 = new Thread(new Runable4());
class Runable3 implements Runnable{
    @Override
    public void run() {
        Log.d(TAG, "RUN3---start" + System.currentTimeMillis());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "RUN3---end" + System.currentTimeMillis());
    }
}
class Runable4 implements Runnable{
    @Override
    public void run() {
        Log.d(TAG, "RUN4---start" + System.currentTimeMillis());
        try {
            thread3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "RUN4---end" + System.currentTimeMillis());
    }
}
public void joinTest(){
    thread3.start();
    thread4.start();
}
sleep关键字
/**
 * sleep关键字
 * sleep关键字使调用线程进入休眠状况,但在一个synchronized中履行sleep,线程虽然会休眠,可是不会开释资源锁
 * 若runable5先运转,则ruanable6要比及runable5sleep完结才干履行同步代码块中的代码
 * D/ThreadTestForJava: RUN5---start1644567514833
 * D/ThreadTestForJava: RUN5---end1644567524837
 * D/ThreadTestForJava: RUN6---start1644567524838
 * D/ThreadTestForJava: RUN6---end1644567524840
 */
class Runable5 implements Runnable{
    @Override
    public void run() {
        Log.d(TAG, "RUN5---start" + System.currentTimeMillis());
        synchronized (obj){
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.d(TAG, "RUN5---end" + System.currentTimeMillis());
    }
}
class Runable6 implements Runnable{
    @Override
    public void run() {
        synchronized (obj){
            Log.d(TAG, "RUN6---start" + System.currentTimeMillis());
            Log.d(TAG, "RUN6---end" + System.currentTimeMillis());
        }
    }
}
public void sleepTest(){
    Thread thread3 = new Thread(new Runable5());
    Thread thread4 = new Thread(new Runable6());
    thread3.start();
    thread4.start();
}
主线程向子线程通讯
/**
 * ===============================================================
 * 主线程向子线程通讯
 * 日志
 * D/ThreadTestForJava: Thread: 123
 * 子线程需求自己保护loop
 * Looper.prepare();
 *             synchronized (HandlerThread.this){
 *                 looper = Looper.myLooper();
 *                 notify();
 *             }
 *             Looper.loop();
 *为了避免looper为空,所以在获取loop的办法中参加wait,可是在主线程等候时刻过长会引发RNA,所以先要调用start在去获取looper
 * ===============================================================
 */
class HandlerThread extends Thread{
    public HandlerThread(){
        super("123");
    }
    private Looper looper;
    public Looper getLooper() {
        synchronized (HandlerThread.this){
            if(looper == null && !isAlive()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return looper;
    }
    @Override
    public void run(){
        Looper.prepare();
        synchronized (HandlerThread.this){
            looper = Looper.myLooper();
            notify();
        }
        Looper.loop();
    }
}
public void testHandlerThread(){
    HandlerThread handlerThread = new HandlerThread();
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper()){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            Log.d(TAG, "Thread: " + Thread.currentThread().getName());
        }
    };
    handler.sendEmptyMessage(1);
}
fun testAtomic(){
    val runable = Runnable {
        for (i in 0 until 10000){
            ThreadSafeTest.addAtomic()
            ThreadSafeTest.addVolatile()
        }
    }
    val thread1 = Thread(runable)
    val thread2 = Thread(runable)
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    println("atomicCount ${ThreadSafeTest.atomicCount.get()}")
    println("count ${ThreadSafeTest.count}")
}

线程锁与Volatile

java中线程锁能够根据功用分类为以下几种

Android常用多线程解析(二)线程安全
其实首要便是 Synchronized 和 ReentrantLock

Android常用多线程解析(二)线程安全

Atomic

Android常用多线程解析(二)线程安全

原子类和Volatile

原子类,CAS 完结无锁数据更新,自旋的设置能够有用避免线程因堵塞-唤醒带来的体系资源开支

适用场景:多线程计数,原子操作,并发数量小的场景

Volatile润饰的成员变量在每次线程拜访时,都逼迫从同享内存从头读取该成员的值,并且,当成员变量值发生改变时,逼迫将改变的值从头写入同享内存。

不能解决非原子操作的线程安全性。功能不及原子类高。

/**
 *原子类和volatile润饰
 * 原子类完结无锁更新,自旋的规划能够有用避免线程堵塞,唤醒带来的资源浪费
 * 适用于多线程计数,原子操作,并发数量小,读操作多的场景
 * volatile润饰的成员变量在每次线程拜访时,都逼迫从同享内存从头读取该成员的值,并且,当成员变量值发生改变时,逼迫改变的值从头写入同享内存
 * 非原子操作对其他线程不可见
 *
 * 在下面的代码中,两个线程分别对原子类和Volatile润饰的成员变量++,最终成果应该都是20000
 * 可是Volatile润饰的成员变量最终成果却不是20000,这是由于其他线程无法拿到非原子操作后的值,导致自增犯错
 *
 *
 * atomicCount 20000
    count 17974
 */
object  ThreadSafeTest {
    val atomicCount : AtomicInteger = AtomicInteger()
    @Volatile
    var count = 0
    fun addAtomic(){
        atomicCount.getAndIncrement()
    }
    fun addVolatile(){
        count++
    }
}
Synchronized线程锁
  • 锁办法,加在办法上,未获取到目标锁的其他线程都不能够拜访该办法。(如果多个实例还是会呈现线程问题)
synchronized void printThreadName(){}
  • 锁class目标,家在static办法上相当于给Class目标加锁,哪怕是不同的java目标实例,也需求排队履行
static synchronized void printThreadName(){}
  • 锁代码块,未获取到目标锁的其他线程能够履行代码块之外的代码
void printThreadNam(){
    String name = Thread.currentThread().getName();
    System.out.print("线程" + name + "预备好了");
    synchronized(this){
    }
}
/**
 *1.无任何线程安全的状况下,五个线程一起拜访printTick
 * 代码如下
 *   fun printTick(){
    println("Thread_${Thread.currentThread().name}预备好了。。。")
    Thread.sleep(1000)
    println("Thread_${Thread.currentThread().name}买了${ticks.removeAt(0)}")
    }
 *
 * 成果入下
 Thread_Thread-0预备好了。。。
Thread_Thread-2预备好了。。。
Thread_Thread-4预备好了。。。
Thread_Thread-1预备好了。。。
Thread_Thread-3预备好了。。。
Thread_Thread-0买了第0张票
Thread_Thread-2买了第0张票
Thread_Thread-1买了第3张票
Thread_Thread-4买了第0张票
Thread_Thread-3买了第0张票
 *呈现重复购票
 * 2.在办法上加了同步锁
@Synchronized
fun printTick(){
println("Thread_${Thread.currentThread().name}预备好了。。。")
Thread.sleep(1000)
println("Thread_${Thread.currentThread().name}买了${ticks.removeAt(0)}")
}
 成果如下
Thread_Thread-0预备好了。。。
Thread_Thread-0买了第0张票
Thread_Thread-4预备好了。。。
Thread_Thread-4买了第1张票
Thread_Thread-3预备好了。。。
Thread_Thread-3买了第2张票
Thread_Thread-2预备好了。。。
Thread_Thread-2买了第3张票
Thread_Thread-1预备好了。。。
Thread_Thread-1买了第4张票
同步代码块中的代码值答应一个线程拜访,这个锁仅仅目标锁,调用不同目标的同步办法,也会呈现线程不安全的状况
for(i in 0 until 5){
Thread(Runnable {
SynchronizedTest().printTick()
}).start()
}
 不同目标调用同步锁的代码
Thread_Thread-0预备好了。。。
Thread_Thread-3预备好了。。。
Thread_Thread-2预备好了。。。
Thread_Thread-1预备好了。。。
Thread_Thread-4预备好了。。。
Thread_Thread-0买了第0张票
Thread_Thread-2买了第0张票
Thread_Thread-4买了第0张票
Thread_Thread-3买了第0张票
Thread_Thread-1买了第0张票
 无法起到线程安全
 3.若同步锁放在静态办法上则会锁住class,在jvmclass只要一份,所以不同目标也会线程安全
4.若同步锁只效果与部分代码块,则不在同步代码块中的代码将无法确保线程安全,同步代码块之后的办法也能够取得线程安全
fun printTick(){
println("Thread_${Thread.currentThread().name}预备好了。。。")
synchronized(this){
Thread.sleep(1000)
println("Thread_${Thread.currentThread().name}买了${ticks.removeAt(0)}")
}
println("Thread_${Thread.currentThread().name}完毕了。。。")
}
Thread_Thread-1预备好了。。。
Thread_Thread-3预备好了。。。
Thread_Thread-2预备好了。。。
Thread_Thread-0预备好了。。。
Thread_Thread-4预备好了。。。
Thread_Thread-1买了第0张票
Thread_Thread-1完毕了。。。
Thread_Thread-4买了第1张票
Thread_Thread-4完毕了。。。
Thread_Thread-0买了第2张票
Thread_Thread-0完毕了。。。
Thread_Thread-2买了第3张票
Thread_Thread-2完毕了。。。
Thread_Thread-3买了第4张票
Thread_Thread-3完毕了。。。
synchronized优势,无需关怀开释锁,jvm会为咱们自动开释,
 下风:有必要比及获取锁目标线程履行完结,或许呈现异常,才干开释掉,不能中途开释,不能中止一个正在
 企图取得锁的线程,别的也不知道多个线程竞赛锁的时分获取锁成功与否,每个锁仅有单一的条件,不能设定超时
 */
class SynchronizedTest(){
    companion object{
        val ticks = mutableListOf<String>()
    }
    fun printTick(){
        println("Thread_${Thread.currentThread().name}预备好了。。。")
        synchronized(this){
            Thread.sleep(1000)
            println("Thread_${Thread.currentThread().name}买了${ticks.removeAt(0)}")
        }
        println("Thread_${Thread.currentThread().name}完毕了。。。")
    }
    init {
        for(i in 0 until 5){
            ticks.add("第${i}张票")
        }
    }
}
fun testSynchronized(){
    val synchronizedTest = SynchronizedTest()
    for(i in 0 until 5){
        Thread(Runnable {
            synchronizedTest.printTick()
        }).start()
    }
}

synchronized的优势

  • 哪怕咱们同步办法中呈现异常,jvm也能够为咱们自动开释锁,能自动从而规避死锁。不需求开发者手动开释锁 下风
  • 有必要要比及获取锁的目标的线程履行完结,或许呈现异常,才干开释掉。不能中途开释锁,不能中止一个正在企图取得锁的进程
  • 别的也不知道多个线程竞赛锁的时分,获取锁成功与否,所以不够灵活
  • 每个锁仅有单一的条件(某个目标)不能设定超时。
ReentrantLock 悲观锁,可重入锁,公正锁,非公正锁
  • 根本用法
ReentrantLock lock = new ReentrantLock()
try{
    lock.lock()
}finally{
    lock.unLock()
}
void lock()//获取不到会堵塞
boolean tryLock()//测验获取锁,成功返回true。
boolean tryLock(3000, TimeUnit.MILLISECONDS)//在必定时刻内不断去测验获取锁
void lockInterruptibly();//可运用Thread.interrupt()打断堵塞状况,退出竞赛,让给其他线程
  • 可重入,避免死锁
ReentrantLock lock = new ReentrantLock()
public void doWork(){
    try{
        lock.lock()
        doWork();//递归,使得统一线程屡次取得锁
    }finally{
        lock.unLock()
    }
}
/**
 * 可重入锁
 * 答应同一个线程在不开释锁的状况下,再次获取锁,避免锁死
打印第一张 Thread-0
打印第二张 Thread-0
打印第三张 Thread-0
打印第四张 Thread-0
打印第五张 Thread-0
打印第一张 Thread-2
打印第二张 Thread-2
打印第三张 Thread-2
打印第四张 Thread-2
打印第五张 Thread-2
打印第一张 Thread-7
打印第二张 Thread-7
打印第三张 Thread-7
打印第四张 Thread-7
打印第五张 Thread-7
打印第一张 Thread-3
打印第二张 Thread-3
打印第三张 Thread-3
打印第四张 Thread-3
打印第五张 Thread-3
打印第一张 Thread-6
打印第二张 Thread-6
打印第三张 Thread-6
打印第四张 Thread-6
打印第五张 Thread-6
打印第一张 Thread-5
打印第二张 Thread-5
打印第三张 Thread-5
打印第四张 Thread-5
打印第五张 Thread-5
打印第一张 Thread-9
打印第二张 Thread-9
打印第三张 Thread-9
打印第四张 Thread-9
打印第五张 Thread-9
打印第一张 Thread-1
打印第二张 Thread-1
打印第三张 Thread-1
打印第四张 Thread-1
打印第五张 Thread-1
打印第一张 Thread-8
打印第二张 Thread-8
打印第三张 Thread-8
打印第四张 Thread-8
打印第五张 Thread-8
打印第一张 Thread-4
打印第二张 Thread-4
打印第三张 Thread-4
打印第四张 Thread-4
打印第五张 Thread-4
 */
class ReentrantLock2{
    val lock = ReentrantLock()
    fun simpleUse(){
        try{
            lock.lock()
            println("打印第一张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
            lock.lock()
            println("打印第二张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
            lock.lock()
            println("打印第三张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
            lock.lock()
            println("打印第四张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
            lock.lock()
            println("打印第五张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
        }finally {
            /**
             * 加锁几次,就要解锁几次
             */
            lock.unlock()
            lock.unlock()
            lock.unlock()
            lock.unlock()
            lock.unlock()
        }
    }
}
/**
 * 可重入锁
 */
private fun test2(){
    val lockTest2 = ReentrantLockTest.ReentrantLock2()
    val run = Runnable {
        lockTest2.simpleUse()
    }
    for(i in 0 until 10){
        Thread(run).start()
    }
}
  • 公正锁与非公正锁
  • 公正锁,一切进入堵塞的线程呢排队一次均有时机履行
  • 默认非公正锁,答应线程插队,避免每个线程都进入堵塞,在唤醒,功能高,由于线程能够插队,导致行列中或许存在线程饿死的状况,一向得不到锁,一向得不到履行
ReentrantLock lock = new ReentrantLock(true/false)
/**
 * ReentrantLock默认为非公正锁
 * 公正锁:一切进入堵塞的线程排队一次均有时机履行
 * 非公正锁:答应线程插队,避免每一个线程都进入堵塞,在唤醒,功能高。由于线程能够插队,导致行列中或许会存在线程饿死的状况,一向得不到锁,一向得不到履行
 * 可重入锁:答应同一个线程在不开释锁的状况下,再次获取锁,避免锁死
 */
/**
 * 公正锁---非公正锁
 * 运用非公正锁,在线程中开释了锁又当即获取锁,会优先履行
 打印第一张 Thread-0
打印第二张 Thread-0
打印第一张 Thread-4
打印第二张 Thread-4
打印第一张 Thread-9
打印第二张 Thread-9
打印第一张 Thread-8
打印第二张 Thread-8
打印第一张 Thread-7
打印第二张 Thread-7
打印第一张 Thread-2
打印第二张 Thread-2
打印第一张 Thread-5
打印第二张 Thread-5
打印第一张 Thread-1
打印第二张 Thread-1
打印第一张 Thread-6
打印第二张 Thread-6
打印第一张 Thread-3
打印第二张 Thread-3
 **
 * 运用公正锁,每个线程都有相同的时机获取锁,线程一旦开释了锁,那么就会进入等候,将锁给予其他线程
打印第一张 Thread-1
打印第一张 Thread-9
打印第一张 Thread-4
打印第一张 Thread-3
打印第一张 Thread-5
打印第一张 Thread-6
打印第一张 Thread-0
打印第一张 Thread-7
打印第一张 Thread-8
打印第一张 Thread-2
打印第二张 Thread-1
打印第二张 Thread-9
打印第二张 Thread-4
打印第二张 Thread-3
打印第二张 Thread-5
打印第二张 Thread-6
打印第二张 Thread-0
打印第二张 Thread-7
打印第二张 Thread-8
打印第二张 Thread-2
 */
class ReentrantLock1{
    val lock = ReentrantLock(true)
    fun simpleUse(){
        try{
            lock.lock()
            println("打印第一张 ${Thread.currentThread().name}")
            Thread.sleep(1000)
            lock.unlock()
            lock.lock()
            println("打印第二张 ${Thread.currentThread().name}")
        }finally {
            lock.unlock()
        }
    }
}
/**
 * 公正锁,非公正锁
 */
private fun testSimpleUns(){
    val lockTest1 = ReentrantLockTest.ReentrantLock1()
    val run = Runnable {
        lockTest1.simpleUse()
    }
    for(i in 0 until 10){
        Thread(run).start()
    }
}
  • Condition条件唤醒
  • 可运用它的awit-singnal指定唤醒一个线程。比较于wait-notify要么悉数唤醒,要么只能唤醒一个,愈加灵活可控。
ReentrantLock lock = new ReentrantLock()
Condition worker1 = lock.newCondition();
Condition worker2 = lock.newCondition();
class Worker1{
    worker1.awit()//进入堵塞,等候唤醒
}
class Worker2{
    worker2.awit()//进入堵塞,等候唤醒
}
class Boss{
    if(...){
        worker1.signal()//指定唤醒线程1
    }else{
        worker2.signal()//指定唤醒线程2
    }
}
/**
 * 运用Condition条件目标,精密操控ReentrantLock
 * 可运用它的await-singnal指定唤醒一个线程,比较wait-notify要么悉数唤醒,要么智能唤醒一个,愈加灵活
 * 案例,出产者线程产生数据,偶数唤醒线程1,基数唤醒线程2
 * await会开释锁,所以出产者线程中也需求参加Condition
 *
没砖了,work1开端歇息了
没砖了,work2开端歇息了
出产出来了workNumber44,唤醒work2
work2开端搬砖: workNumber:44
work2开释锁
没砖了,work2开端歇息了
出产出来了workNumber98,唤醒work2
work2开端搬砖: workNumber:98
work2开释锁
没砖了,work2开端歇息了
出产出来了workNumber63,唤醒work1
work1开端搬砖: workNumber:63
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber13,唤醒work1
work1开端搬砖: workNumber:13
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber3,唤醒work1
work1开端搬砖: workNumber:3
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber9,唤醒work1
work1开端搬砖: workNumber:9
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber73,唤醒work1
work1开端搬砖: workNumber:73
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber27,唤醒work1
work1开端搬砖: workNumber:27
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber97,唤醒work1
work1开端搬砖: workNumber:97
work1开释锁
没砖了,work1开端歇息了
出产出来了workNumber63,唤醒work1
work1开端搬砖: workNumber:63
work1开释锁
没砖了,work1开端歇息了
 */
class ReentrantLock3{
    @Volatile
    var workNumber = 0
    val lock = ReentrantLock(false)
    val condition1 = lock.newCondition()
    val condition2 = lock.newCondition()
    val condition3 = lock.newCondition()
    fun work1(){
        try {
            lock.lock()
            if(workNumber == 0 || workNumber % 2 == 0) {
                println("没砖了,work1开端歇息了")
                condition1.await()
                condition3.signal()
            }
            println("work1开端搬砖: workNumber:${workNumber} ")
            workNumber = 0
        }finally {
            println("work1开释锁")
            lock.unlock()
        }
    }
    fun work2(){
        try {
            lock.lock()
            if(workNumber == 0 || workNumber % 2 != 0){
                println("没砖了,work2开端歇息了")
                condition2.await()
                condition3.signal()
            }
            println("work2开端搬砖: workNumber:${workNumber} ")
            workNumber = 0
        }finally {
            println("work2开释锁")
            lock.unlock()
        }
    }
    fun boos(){
        try {
            lock.lock()
            workNumber = (0..100).random()
            if(workNumber % 2 == 0){
                condition2.signal()
                println("出产出来了workNumber${workNumber},唤醒work2")
            }else{
                condition1.signal()
                println("出产出来了workNumber${workNumber},唤醒work1")
            }
            condition3.await()
        }finally {
            lock.unlock()
        }
    }
}
/**
 * Condition条件唤醒
 */
private fun test3(){
    val count = AtomicInteger()
    val lockTest3 = ReentrantLockTest.ReentrantLock3()
    Thread(Runnable {
        count.getAndIncrement()
        while(true){
            lockTest3.work1()
        }
    }).start()
    Thread(Runnable {
        count.getAndIncrement()
        while (true){
            lockTest3.work2()
        }
    }).start()
    Thread.sleep(1000)
    for(i in 0 until 10){
        lockTest3.boos()
    }
}
  • ReentrantReadWriteLock 同享锁,排他说
  • 同享锁,一切线程均可一起取得,并发量高,比方在线检查文档
  • 排他锁,同一时刻只要一个线程有权修正资源,比方在线文档编辑
ReentrantReadWriteLock reentrantReadWriteLock
ReentrantReadWriteLock.ReadLock readLock
ReentrantReadWriteLock.WriteLock writeLock
/**
 * 同享锁,一切线程均可一起取得,并发量高,比方在线文档检查
 * 排他锁,同一时刻只要一个线程有权修正资源,比方在线文档编辑
Thread Thread-2 开端写
Thread Thread-2 开释写锁
Thread Thread-6 开端写
Thread Thread-6 开释写锁
Thread Thread-3 开端写
Thread Thread-3 开释写锁
Thread Thread-7 开端写
Thread Thread-7 开释写锁
Thread Thread-1 开端写
Thread Thread-1 开释写锁
Thread Thread-4 开端写
Thread Thread-4 开释写锁
Thread Thread-9 开端写
Thread Thread-9 开释写锁
Thread Thread-0 开端写
Thread Thread-0 开释写锁
Thread Thread-8 开端写
Thread Thread-8 开释写锁
Thread Thread-5 开端写
Thread Thread-5 开释写锁
Thread Thread-2 开端阅览
Thread Thread-4 开端阅览
Thread Thread-6 开端阅览
Thread Thread-0 开端阅览
Thread Thread-5 开端阅览
Thread Thread-1 开端阅览
Thread Thread-7 开端阅览
Thread Thread-3 开端阅览
Thread Thread-9 开端阅览
Thread Thread-8 开端阅览
Thread Thread-5 开释读锁
Thread Thread-6 开释读锁
Thread Thread-2 开释读锁
Thread Thread-0 开释读锁
Thread Thread-1 开释读锁
Thread Thread-9 开释读锁
Thread Thread-7 开释读锁
Thread Thread-3 开释读锁
Thread Thread-8 开释读锁
Thread Thread-4 开释读锁
 */
class ReentrantReadWriteLockTest{
    val reentrantReadWriteLock = ReentrantReadWriteLock()
    val reentrantReadLock = reentrantReadWriteLock.readLock()
    val reentrantWriteLock = reentrantReadWriteLock.writeLock()
    fun readWork(){
        try{
            reentrantReadLock.lock()
            println("Thread ${Thread.currentThread().name} 开端阅览")
            Thread.sleep(1000)
        }finally {
            println("Thread ${Thread.currentThread().name} 开释读锁")
            reentrantReadLock.unlock()
        }
    }
    fun writeWork(){
        try{
            reentrantWriteLock.lock()
            println("Thread ${Thread.currentThread().name} 开端写")
            Thread.sleep(1000)
        }finally {
            println("Thread ${Thread.currentThread().name} 开释写锁")
            reentrantWriteLock.unlock()
        }
    }
}
/**
 * 排他锁
 * 同享锁
 */
private fun test4(){
    val reentrantReadWriteLockTest = ReentrantLockTest.ReentrantReadWriteLockTest()
    for(i in 0 until 10){
        Thread(Runnable {
            reentrantReadWriteLockTest.readWork()
        }).start()
    }
//    for(i in 0 until 10){
//        Thread(Runnable {
//            reentrantReadWriteLockTest.writeWork()
//        }).start()
//    }
}

如何正确运用锁&原子类

  • 减少持锁时刻 尽管锁在同一时刻只能答应一个线程持有,其他想要占用锁的线程都在临界区外等候锁开释,这个等候的时刻根据实践的运用及代码写法可长可短
    public void syncMethod(){
        noneLockedCode();//2s
        synchronized(this){
            needLockedMethed();//2s
        }
        noneLockedCode2;//2s
    }
    
  • 锁分离 读读,读写,写读,写写。只要有些锁进入才需求做同步处理,可是关于大多数运用,读的场景远大于写。因此运用读写锁,在读多写少的场景中,就能够很好的进步体系的功能。这便是锁分离
  • 锁粗化 屡次加锁
public void doSomethingMethod(){
    synchronized(lock){
        //do some thing
    }
    ...
    //这儿还有一些代码,做其他不需求同步的工作,单能很快履行完结
    ...
    synchronized(lock){
        //do other thing
    }
}
//粗化
public void doSomethingMethod(){
    synchronized(lock){
        //do some thing
        ...
        //这儿还有一些代码,做其他不需求同步的工作,单能很快履行完结
        ...
        //do other thing
    }
}

其他操控

CountDownLatch
/**
 Thread 开端运转Thread-3
Thread 开端运转Thread-4
Thread 开端运转Thread-2
Thread 开端运转Thread-1
Thread 开端运转Thread-0
Thread 完毕运转Thread-2
Thread 完毕运转Thread-3
Thread 完毕运转Thread-4
Thread 完毕运转Thread-0
Thread 完毕运转Thread-1
一切线程运转完毕
 CountDownLatch创立时需求指定一个int值,调用await的线程将被堵塞,直到其他线程调用countDown()办法将指定int值减为0时才干回复运转
 */
private fun countDownLatchTest(){
    val countDownLatch = CountDownLatch(5)
    for(i in 0 until 5){
        Thread(Runnable {
            println("Thread 开端运转${Thread.currentThread().name}")
            Thread.sleep((2000 .. 6000).random().toLong())
            println("Thread 完毕运转${Thread.currentThread().name}")
            countDownLatch.countDown()
        }).start()
    }
    countDownLatch.await()
    println("一切线程运转完毕").run {  }
    countDownLatch.let {  }
}
Semaphore
/**
Thread 开端运转Thread-1
Thread 开端运转Thread-0
Thread 开端运转Thread-5
Thread 完毕运转Thread-0
Thread 开端运转Thread-2
Thread 完毕运转Thread-1
Thread 开端运转Thread-3
Thread 完毕运转Thread-5
Thread 开端运转Thread-7
Thread 完毕运转Thread-3
Thread 开端运转Thread-9
Thread 完毕运转Thread-7
Thread 开端运转Thread-6
Thread 完毕运转Thread-2
Thread 开端运转Thread-8
Thread 完毕运转Thread-8
Thread 开端运转Thread-4
Thread 完毕运转Thread-6
Thread 完毕运转Thread-9
Thread 完毕运转Thread-4
Semaphore类似与令牌,创立时需指定令牌数量和是否时公正的,当一个线程运用semaphore.acquire()获取到令牌后能够继续履行,
当令牌被获取完后需求等候其他线程开释令牌才干运转
 */
private fun semaphoreTest(){
    val semaphore = Semaphore(3, true)
    for(i in 0 until 10){
        Thread(Runnable {
            semaphore.acquire()
            println("Thread 开端运转${Thread.currentThread().name}")
            Thread.sleep((2000 .. 6000).random().toLong())
            println("Thread 完毕运转${Thread.currentThread().name}")
            semaphore.release()
        }).start()
    }
}