JAVA多线程高并发2

2021-02-07
完结篇,建议先看我的第一篇多线程高并发~~

1.CPU轮询调度,哪个线程获得CPU时间片,获得CPU时间片的线程执行。主线程main,其他线程

并行:多核cpu,同一时刻多个线程一起执行 并发:在同一个核心,cpu在多个线程之间切换,看哪个线程获取了cpu的时间片则执行。

2.TimeUnit.MILLISECONDS.sleep(1000); TimeUnit.SECONDS.sleep(1); 睡眠1s

3.创建线程3种方式:继承Thread类重写run()方法,实现Runable接口重写run()方法,线程池(Executors线程池工厂)

public class Thread02 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("创建线程的第一种方式");
            }
        };

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("创建线程的第二种方式");
            }
        });

        ExecutorService service = Executors.newFixedThreadPool(2);
        for(int i = 0;i<5;i++){
            int k = i;
            service.submit(()->{
                System.out.println("创建线程的第三种方式"+k);
            });
        }
        service.shutdown();

        t.start();
        t2.start();
        System.out.println("主线程");

    }
}

3.Thread.sleep(), t.join(), Thread.yield()

sleep:线程睡眠,但是不会释放资源,睡眠时间到后线程接着运行,不会释放cpu时间片

t.join:等待t线程执行完后再继续执行

yield:线程让步,让出当前cpu,再和其他线程一起竞争cpu,可能下次还是这个线程获得cpu继续执行

public class Thread03 {
    private static void testSleep(){
        Thread t = new Thread(()->{
            try {
                System.out.println(System.currentTimeMillis());
                Thread.sleep(10000);
                System.out.println(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();
    }

    private static void testJoin(){
        Thread t1 = new Thread(()->{
            for(int i=0;i<30;i++){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        },"t1");

        Thread t2 = new Thread(()->{
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0;i<30;i++){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        },"t2");

        t1.start();
        t2.start();
    }

    private static void testYield(){
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    try {
                        TimeUnit.MILLISECONDS.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" "+i);
                    Thread.yield();
                }
            }
        },"t1");

        Thread t2= new Thread(()->{
            for(int i=0;i<10;i++){
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
                Thread.yield();
            }
        },"t2");

        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        //testSleep();
        //testJoin();
        testYield();
    }
}

4.线程6种状态

可以通过t.getState() 来获取当前线程的状态

New、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

NEW:线程被创建出来还没有被调用start()时候的状态

RUNNABLE:当线程被调用了start(),且处于等待操作系统分配资源(如CPU)、正在运行状态,即表示Running状态和Ready

BLOCKED:进入synchronized块/方法,锁被其它线程占有,这个时候被操作系统挂起,状态为阻塞状态

WAITING:当线程调用wait()/join()/LockSupport.park()不加超时时间的方法之后所处的状态,当前状态的线程不会被分配CPU资源和持有锁

TIMED_WAITING:线程调用sleep(睡眠时间)/wait(等待时间)/join(等待时间)/ LockSupport.parkNanos(等待时间)/LockSupport.parkUntil(等待时间)方法之后所处的状态,在指定的时间没有被唤醒或者等待线程没有结束,会被系统自动唤醒,正常退出

TERMINATED:线程执行结束

在这里插入图片描述

5.工作空间:Java内存模型分为主内存,和工作内存。主内存是所有的线程所共享的,工作内存是每个线程自己有一个,不是共享的。每个线程从主内存把变量拷贝到自己的工作内存,修改完后再把变量写回到主内存。

线程安全:多个线程对同一个变量进行修改,得到不正确的结果,是线程不安全的。

6.同步代码块和同步方法:同一时刻只允许一个线程访问同步代码块和同步方法。获得对象的锁,获取本身所this,获取类所.class。

同步代码块和同步方法都有静态和非静态。非静态:同步方法等同于synchronized(this),静态的等同于synchronized(.class)

public class Thead05 {
    private static int a=50;
    private static void m(){
        //静态同步代码块,获取类的锁
        synchronized (Thead05.class){
            a--;
            System.out.println(Thread.currentThread().getName()+" "+a);
        }
    }
	
    //静态同步方法
    synchronized private static void m2(){
            a--;
            System.out.println(Thread.currentThread().getName()+" "+a);
    }

    public static void main(String[] args) {
        for(int i=0;i<50;i++){
            new Thread(()->{
                m2();  //m();
            }).start();

        }
    }
}
public class Thread04 {
    private final Object o = new Object();
    int a=10;
    int b=10;

    //等价于synchronized(this)
    synchronized void m1(){
            a--;
            System.out.println(Thread.currentThread().getName()+" "+a);
    }

    void m2(){
        synchronized (this){
            b--;
            System.out.println(Thread.currentThread().getName()+" "+b);
        }
    }

    void m3(){
        synchronized (o){
            b--;
            System.out.println(Thread.currentThread().getName()+" "+b);
        }
    }

    void m4(){
        synchronized (Thread04.class){
            b--;
            System.out.println(Thread.currentThread().getName()+" "+b);
        }
    }

    public static void main(String[] args) {
        Thread04 t04 = new Thread04();
        for(int i = 0;i<5;i++){
            int k = i;
            new Thread(()->{
                t04.m1();
            },"线程"+k).start();
        }

        for(int i=0;i<5;i++){
            new Thread(()->{
                t04.m4();
            }).start();
        }
    }
}

7.可重入锁:某个线程已经获得某个锁,可以再次获取相同的锁而不会出现死锁。synchronized和ReentrantLock都是可重入的

ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样

public class T {
	synchronized void m1() {
		System.out.println("m1 start");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		m2();
		System.out.println("m1 end");
	}
	
	synchronized void m2() {
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m2");
	}

	public static void main(String[] args) {
		new T().m1();
	}
}

8.synchronized抛出异常锁会被释放

9.synchronized底层实现原理:每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权。monitorexit 释放所有权。通过monitorenter和monitorexit 两条jvm指令来实现的。

  • 线程解锁前,必须把共享变量的最新值刷新到主内存中
  • 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时,需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)

10.volitate:mesi(缓存一致性),禁止指令重排序。适用范围:对变量的写入操作不依赖其当前值

11.区别:synchronized既能够保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。

10.锁升级:jdk早期重量级锁(系统级别),偏向锁->自旋锁(有竞争)->重量级锁(旋转10次)

11.采用细粒度的锁,可以使线程争用时间变短,从而提高效率。在需要的地方上锁,而不是整个方法上锁,提高线程执行效率

12.AtomicInteger,AtomicLong , AtomicBoolean, LongAdder 都是原子性操作,底层是CAS。LongAdder 比 AtomicLong 效率更高

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Thread07 {
    private AtomicInteger atomic = new AtomicInteger(0);
    List<Thread> list = new LinkedList<Thread>();

    public void m(){
        for(int i=0;i<10000;i++){
            atomic.incrementAndGet();
        }
    }

    public static void main(String[] args) {
        Thread07 t07 = new Thread07();
        List<Thread> list = t07.list;
        for(int i=0;i<100;i++){
            list.add(new Thread(t07::m));
        }

        list.forEach((o)->{o.start();});

        list.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t07.atomic);
    }
}
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

public class Thread08 {
    private AtomicLong count = new AtomicLong();
    private LongAdder count1 = new LongAdder();

    public void m(){
        for(int i=0;i<1000000;i++){
            count.incrementAndGet();
        }
    }

    public void m1(){
        for(int i=0;i<1000000;i++){
            count1.increment();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread08 t08 = new Thread08();
        Thread[] arr = new Thread[100];

        //测试AtomicLong
        for(int i=0;i<arr.length;i++){
            arr[i] = new Thread(t08::m);
        }
        long start = System.currentTimeMillis();
        for(Thread t:arr){
            t.start();
        }
        for(Thread t:arr){
            t.join();
        }
        long end = System.currentTimeMillis();
        System.out.println((end-start)+" "+t08.count);  // 2099 100000000

        //测试LongAdder
        for(int i=0;i<arr.length;i++){
            arr[i] = new Thread(t08::m1);
        }
        long start1 = System.currentTimeMillis();
        for(Thread t:arr){
            t.start();
        }
        for(Thread t:arr){
            t.join();
        }
        long end1 = System.currentTimeMillis();
        System.out.println((end1-start1)+" "+t08.count1); // 274 100000000

    }
}

13.ReentrantLock :公平锁(true)非公平锁(false)默认非公平锁,可重入锁(加锁和解锁次数要一致)

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Thread09 {
    //true 为公平锁,false为非公平锁。在等待队列最前的线程获得锁为公平锁,否则为抢占式
    private ReentrantLock reentrantLock = new ReentrantLock(false);

    void m1(){
        for(int i=0;i<26;i++){
            try{
                reentrantLock.lock();  //加锁
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.print(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();  //释放锁
            }
        }
    }

    void m2(){
        char a = 'A';
        for(int i=a;i<a+26;i++){
            try{
                reentrantLock.lock();
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.print((char) i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Thread09  t09 = new Thread09();
        Thread t = new Thread(t09::m1);
        Thread t2 = new Thread(t09::m2);
        t.start();
        t2.start();
        // 公平锁输出: A0B1C2D3E4F5G6H7I8J9K10L11M12N13O14P15Q16R17S18T19U20V21W22X23Y24Z25
        // 非公平锁:不是交替输出
    }
}

lock.tryLock() 尝试获取锁

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Thread10 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        new Thread(()->{
            try {
                lock.lock();
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(()->{
            boolean flag = false;
            try{
                //尝试去获得锁,不管得不得到锁,下面的代码仍然会继续执行
                /**
	 				* 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
	 				* 可以根据tryLock的返回值来判定是否锁定
	 				* 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
	 			*/
                flag = lock.tryLock(5,TimeUnit.SECONDS);
                System.out.println("kkkkk");
                System.out.println(flag);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //如果获得锁就释放锁
                if(flag){
                    lock.unlock();
                }
            }
        }).start();
    }
}

14.CountDownLatch:相当于一个计数器,原子性操作。线程执行完毕后计数器递减,当计数器的值为0时,表示所有线程都执行完毕

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.LongAdder;

public class Thread11 {
    public static void main(String[] args) {
        Thread[] arr = new Thread[1000];
        CountDownLatch countDownLatch = new CountDownLatch(arr.length);  //构造方法
        LongAdder adder = new LongAdder();
        for(int i = 0;i<1000;i++){
            arr[i] = new Thread(()->{
                for(int k=0;k<100000;k++){
                    adder.increment();
                }
                countDownLatch.countDown();    //自减操作
            });
        }

        for(Thread t:arr){
            t.start();
        }


        try {
            countDownLatch.await();   //阻塞,等待,直到计数器为0才继续执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        System.out.println(adder);

    }
}

第二个例子

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;

public class CountDownLatchDemo {
    private AtomicLong atomicLong = new AtomicLong(0);
    List<Thread> list = new ArrayList<Thread>();
    public CountDownLatch countDownLatch = new CountDownLatch(100);

    public void addList(Thread t){
        list.add(t);
    }

    public List<Thread> getList(){
        return list;
    }

    public AtomicLong getAtomicLong(){
        return atomicLong;
    }

    public void incre(){
        for(int k=0;k<10000;k++){
            atomicLong.incrementAndGet();
        }
        countDownLatch.countDown();
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatchDemo countDownLatchDemo = new CountDownLatchDemo();
        for(int i=0;i<100;i++){
            /**
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    countDownLatchDemo.incre();
                }
            });
             */
            Thread t = new Thread(countDownLatchDemo::incre);
            countDownLatchDemo.addList(t);
        }

        countDownLatchDemo.getList().forEach((t)->{t.start();});
        countDownLatchDemo.countDownLatch.await();
        System.out.println(countDownLatchDemo.getAtomicLong());   //1000000    10000*100

    }
}

15.CycliBarrier 相当于一个栅栏,人数凑齐之后栅栏才打开,再继续往下执行

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CycliBarrierDemo {

    CyclicBarrier cyclicBarrier = new CyclicBarrier(5,()->{
        System.out.println("CycliBarrier Test");
    });


    public static void main(String[] args) {
        CycliBarrierDemo demo = new CycliBarrierDemo();
        for(int i=0;i<20;i++){
            new Thread(){
                @Override
                public void run() {
                    try {
                        //阻塞住,不往下执行,等到5个之后才继续往下执行
                        demo.cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

    }
}

16.ReadWriteLock 读写锁,这是一个接口,其实现类为ReentrantReadWriteLock。有readlock 读锁和writelock写锁两把锁

读锁是共享锁,写锁是独占锁

获取读锁的条件:没有其他线程的写锁

获取写锁的条件:没有其他线程的读锁,没有其他线程的写锁

一个线程要想同时持有写锁和读锁,必须先获取写锁再获取读锁;写锁可以“降级”为读锁;读锁不能“升级”为写锁。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


public class ReentrantReadWriteLockDemo {

    private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //读锁
    private static Lock readLock = readWriteLock.readLock();
    //写锁
    private static Lock writeLock = readWriteLock.writeLock();

    private static void read()  {
        readLock.lock();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":获取了读锁");
        //释放锁
        readLock.unlock();
    }

    private static void write()  {
        writeLock.lock();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+": 获取了写锁");
        writeLock.unlock();
    }

    /**
     * 此例证明读锁是共享锁,多个线程可以同时获得读锁
     * 写锁是独占锁,排它锁,一个时间内只有一个线程可以获得
     * @param args
     */
    public static void main(String[] args) {
        for(int i = 0 ;i<20;i++){
            new Thread(ReentrantReadWriteLockDemo::read).start();
        }
        for(int i=0;i<3;i++){
            new Thread(ReentrantReadWriteLockDemo::write).start();
        }

    }
}
  1. Semaphore 信号量,可以控制同时访问资源的线程个数,Semaphore的主要方法摘要:

    void acquire() :从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。

    void release():释放一个许可,将其返回给信号量。

    int availablePermits():返回此信号量中当前可用的许可数。

    import java.util.concurrent.Semaphore;
    
    public class SemaphoreDemo {
    
        public static void main(String[] args) {
            Semaphore semaphore = new Semaphore(2);
            Thread[] threads = new Thread[200];
            for(int i=0;i<200;i++){
                threads[i] = new Thread(()->{
                    try {
                        /**
                         * 没有获得信号量的线程阻塞等待,获得信号量信号量--
                         */
                        semaphore.acquire();
                        Thread.sleep(500);
                        System.out.println(Thread.currentThread().getName()+":获得信号量");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //释放信号量,信号量++
                    semaphore.release();
                });
            }
    
            for(int i=0;i<threads.length;i++){
                threads[i].start();
            }
    
    
        }
    }
    
  2. LockingSupport 程中首选看是否有许可,有许可就立马返回,而每次unpark都会给许可设置成有,这意味着,可以先执行unpark,给予许可,再执行park立马自行.

    unpark(Thread thread)释放thread线程的许可证 park() 当前线程获取许可证

    import java.util.concurrent.locks.LockSupport;
    
    public class LockingSupportDemo {
    
        private static Thread t1;
        private static Thread t2;
    
        public static void main(String[] args) {
            int num = 1;
            char letter = 'a';
    
            t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(char letter='a';letter<='z';letter++){
                        System.out.print(letter);
                        LockSupport.unpark(t1);  //释放许可
                        LockSupport.park();
                    }
                }
            });
    
            t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i = 1;i<=26;i++){
                        LockSupport.park();  //获取许可,如果没有许可则阻塞
                        System.out.print(i);
                        LockSupport.unpark(t2);
    
                    }
                }
            });
    
            t1.start();
            t2.start();
    
    
        }
    }
    
    
  3. synchronized 同步代码块,同步方法

    /**
     * 两个线程顺序输出A1B2C3D4...26Z
     * synchronized 同步代码块,用来修饰的方法为同步方法
     * 同一时刻只有一个线程可以获得锁,没有获得锁的线程进入阻塞状态
     * 锁:对象的锁,类的锁 synchronized(A.class),同步方法=synchronized(this){}
     * wait(),notify(),nofityAll()  需要配合synchronized使用
     * wait() 释放锁,线程进入阻塞状态,直到有notify 或者 notifyAll 唤醒,然后去竞争锁
     * nofity() 唤醒在等待队列中最前面的线程,notifyAll() 唤醒在等待队列中的所有线程,然后去竞争这把锁
     *
     */
    
    public class WaitNotifyDemo {
    
        private Object object = new Object();
    
        public void printNumber(int i){
            System.out.print(i);
        }
    
        public void printLetter(char c){
            System.out.print(c);
        }
    
        public static void main(String[] args) {
            WaitNotifyDemo wnd = new WaitNotifyDemo();
            Object o = wnd.object;
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i=1;i<27;i++){
                        synchronized (o){
                            try {
                                wnd.printNumber(i);
                                o.notify();
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
    
                        }
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(char c = 'A'; c<='Z';c++){
                        synchronized (o){
                            try {
                                wnd.printLetter(c);
                                o.notify();
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    
    
    //例子2
    
    public class WaitNofityDemo2 {
        private Object o = new Object();
    
        public void printNumber(){
            for(int i=1;i<27;i++){
                synchronized (o){
                    try {
                        System.out.print(i);
                        o.notifyAll();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public void printLetter(){
            for(char c='A';c<='Z';c++){
                synchronized (o){
                    try {
                        System.out.print(c);
                        o.notifyAll();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            WaitNofityDemo2 waitNofityDemo2 = new WaitNofityDemo2();
            Thread t1 = new Thread(waitNofityDemo2::printNumber);
            Thread t2 = new Thread(waitNofityDemo2::printLetter);
            t1.start();
            t2.start();
        }
    }
    
  4. ReentrantLock

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * Condition 条件队列,signal() 唤醒条件队列最前的线程,去获取锁,signalAll() 唤醒条件队列的所有线程,
     * await() 释放锁,进入条件队列,需要signal() 或者signalAll() 唤醒
     * 可以有多个condition 条件队列
     *
     * ReentrantLock  lock() 获取锁   unlock() 释放锁
     */
    public class ReentrantLockDemo {
        static  ReentrantLock lock;
        static Condition condition;
    
        static{
            lock = new ReentrantLock();
            condition = lock.newCondition();
        }
    
    
        public static void printNumber() {
            for(int i = 1;i<=26;i++){
                try {
                    lock.lock();  //获取锁
                    System.out.print(i);
                    condition.signal();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
            lock.unlock();  //释放锁
        }
    
        public static void printLetter() {
            for(char c = 'A';c<='Z';c++){
                try {
                    lock.lock();  //获取锁
                    System.out.print(c);
                    condition.signal();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
            lock.unlock();  //释放锁
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(ReentrantLockDemo::printNumber);
            Thread t2 = new Thread(ReentrantLockDemo::printLetter);
            t1.start();
            t2.start();
        }
    }
    
  5. 强、软、弱、虚 四种引用

    强:通过new 关键字创建的对象是强引用,jvm内存不足时候也不会对对象进行垃圾回收

    软:jvm内存足够垃圾回收器不会回收,内存不足时,第一次垃圾回收还是内存不足则会回收软引用对象

    弱:被垃圾扫描器扫描到就会回收,不管jvm内存是否足够

    虚:在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动

  6. ThreadLocal 不同线程变量隔离,同一个线程变量共享。set(),get() 方法

    ThreadLocal有静态内部类ThreadLocalMap

    Thread 类有成员变量 ThreadLocal.ThreadLocalMap,set()方法就是往自己的成员变量设置值,get()方法获取值

    ThreadLocalMap的key是this,存储ThreadLocal对象,value是设置的值

    public class ThreadLocalDemo {
        public static void main(String[] args) {
            ThreadLocal<String> threadLocal = new ThreadLocal<>();
            Thread[] threads = new Thread[10];
            for(int i = 0;i<threads.length;i++){
                threads[i] = new Thread(()->{
                    threadLocal.set(Thread.currentThread().getName());
                    System.out.println(threadLocal.get());
    
                });
            }
    //        for(int i = 0;i<threads.length;i++){
    //            threads[i].start();
    //        }
            for(Thread t:threads){
                t.start();
            }
        }
    }
    
    /**
     * 输出:
     * Thread-0
     * Thread-2
     * Thread-1
     * Thread-4
     * Thread-6
     * Thread-5
     * Thread-3
     * Thread-9
     * Thread-8
     * Thread-7
     */
    
  7. 顺序输出A1B2C3… 生产者消费者程序,售票程序

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 生产者消费者
     */
    public class ContainerDemo {
    
        private volatile static List<String> list = new ArrayList<String>();
        private static Object o = new Object();
    
        public static void main(String[] args) {
            new Thread(()->{
                synchronized (o){
                    while(true){
                        if(list.size()<5){
                            list.add(Thread.currentThread().getName());
                        }else{
                            try {
                                o.notifyAll();
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
    
                    }
    
                }
            }).start();
    
            new Thread(()->{
                synchronized (o){
                    while(true){
                        if(list.size()>0){
                            System.out.println(list.remove(0));
                        }else{
                            try {
                                o.notifyAll();
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
    
                    }
    
                }
            }).start();
        }
    
    }
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * 售票程序
     * CAS 保证原子性
     */
    public class SellTicketDemo {
    
        private static AtomicInteger atomicInteger = new AtomicInteger(10000); //cas 保证原子性
        private static int m1;
        private static int m2;
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(()->{
                while(atomicInteger.get()>1){
                    atomicInteger.decrementAndGet();
                    m1++;
                }
    
            });
    
            Thread t2 = new Thread(()->{
                while(atomicInteger.get()>0){
                    atomicInteger.decrementAndGet();
                    m2++;
                }
            });
    
            t1.start();
            t2.start();
    
            t1.join();
            t2.join();
            System.out.println("t1:"+m1);
            System.out.println("t2:"+m2);
            System.out.println(m1+m2);
    
    
        }
    
    }
    
    public class SellTicketDemo2 {
        /**
        *售票2
        *
        */
    
        private static int ticket = 1000000;
    
        private static int win1 = 0;
        private static int win2 = 0;
    
        public synchronized static void win1Sell(){
            if(ticket>0){
                ticket--;
                win1++;
            }
        }
    
        public synchronized static void win2Sell(){
            if(ticket>0){
                ticket--;
                win2++;
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(ticket>0){
                        win1Sell();
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(ticket>0){
                        win2Sell();
                    }
                }
            });
    
            t1.start();
            t2.start();
    
            t1.join();
            t2.join();
    
            System.out.println("win1:"+ win1 + "   win2:"+win2);
            System.out.println(win1+win2);
        }
    }
    
  8. 并发容器

    并编程中,一般需要用到安全的队列,如果要自己实现安全队列,可以使用2种方式:
    方式1:加锁,这种实现方式就是我们常说的阻塞队列。
    方式2:使用循环CAS算法实现,这种方式实现队列称之为非阻塞队列。

    ArrayList:线程不安全 LinkedList:线程不安全 HashMap:线程不安全

    PriorityQueue(线程不安全): 优先级队列。默认排序升序,可以自定义比较器Comparotor实现自定义排序

    HashTable: 线程安全的,每个方法都是同步方法 synchronized 修饰.synchronized来保证线程安全,但在线程竞争激烈的情况下Hashtable的效率非常低下。因为当一个线程访问Hashtable的同步方法时,其他线程访问Hashtable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低.3。(HashMap 线程不安全)

    ConcurrentHashMap: 1.7 segment[] 数组+ HashEntry[] 数组,分段加锁的方式支持每个线程对一部分数据进行操作,加锁的方式是Reentrantlock。jdk1.8 抛弃分段加锁,采用cas+synchronized

    CopyOnWriteArrayList:(写时候synchronized加锁,只有一个线程可以写)写时复制技术,实现读写分离。读的时候不加锁,速度非常快,写的时候会对原来的容器进行一份拷贝,在新的arraylist上修改,再把引用指向新的arraylist。

    读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器

    优点:读写分离,读操作和写操作在不同的容器,读操作不加锁效率非常高。

    缺点:每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据

    Vector:线程安全的ArrayList,方法都用synchronized修饰

    ConcurrentLinkedQueue: cas 保证线程安全

  9. BlockingQueue 阻塞队列

    add() :添加成功返回true,否则抛出异常

    offer():添加成功返回true,失败返回false

    put():如果队列满了会进入阻塞状态

    poll(): 从队列中取值,没有值返回null

    take():从队列中获取值,如果队列中没有值,线程会一直阻塞,直到队列中有值,并且该方法取得了该值

    方法使用ReentrantLock 加锁,保证线程安全

    ArrayBlockingQueue
    LinkedBlockingDeque
    DelayQueue:  时blockingQueue的一种,属于延时队列
    SynchronousQueue: blockingQueue一种,put()方法阻塞,直到队列的元素被消费。如果队列为空take() 方法阻塞。
    
  10. ConcurrentSkipListMap

  11. CompletableFuture

    • 异步任务结束时,会自动回调某个对象的方法;
    • 异步任务出错时,会自动回调某个对象的方法;
    • 主线程设置好回调后,不再关心异步任务的执行

    异步任务,jdk1.8新特性。以前通过FutureTask的get()方法或者Future的get() 方法获取线程的执行结果会阻塞,通过轮询或者阻塞方式去获取结果,造成CPU资源浪费而且不能实时得到结果,有违背异步编程原则。

    import java.io.IOException;
    import java.util.Random;
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    public class T06_01_CompletableFuture {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            long start, end;
    
            /*start = System.currentTimeMillis();
    
            priceOfTM();
            priceOfTB();
            priceOfJD();
    
            end = System.currentTimeMillis();
            System.out.println("use serial method call! " + (end - start));*/
    
            start = System.currentTimeMillis();
    
            CompletableFuture<Double> futureTM = CompletableFuture.supplyAsync(()->priceOfTM());
            CompletableFuture<Double> futureTB = CompletableFuture.supplyAsync(()->priceOfTB());
            CompletableFuture<Double> futureJD = CompletableFuture.supplyAsync(()->priceOfJD());
    
            CompletableFuture.allOf(futureTM, futureTB, futureJD).join();
    
            CompletableFuture.supplyAsync(()->priceOfTM())
                    .thenApply(String::valueOf)
                    .thenApply(str-> "price " + str)
                    .thenAccept(System.out::println);
    
    
            end = System.currentTimeMillis();
            System.out.println("use completable future! " + (end - start));
    
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private static double priceOfTM() {
            delay();
            return 1.00;
        }
    
        private static double priceOfTB() {
            delay();
            return 2.00;
        }
    
        private static double priceOfJD() {
            delay();
            return 3.00;
        }
    
        /*private static double priceOfAmazon() {
            delay();
            throw new RuntimeException("product not exist!");
        }*/
    
        private static void delay() {
            int time = new Random().nextInt(500);
            try {
                TimeUnit.MILLISECONDS.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.printf("After %s sleep!\n", time);
        }
    }
    
    
    • ForkJoinPool 用来执行ForkJoinTask,实现类有RecursiveTask(有返回值任务),RecursiveAction(无返回值任务),重写compute方法
    • ForkJoinTask的fork()方法:添加到线程池异步执行此任务 join():等待返回结果,同步阻塞,也可以使用get(),同步阻塞
    • 可以使用ForkJoinPool.execute(异步,不返回结果)/invoke(同步,返回结果)/submit(异步,返回结果)方法,来执行ForkJoinTask
  12. 线程池

    线程池工厂:Executors

    自定义线程池ThreadPoolExecutor

    execute和submit 都是异步方法

    newCachedThreadPool

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    

    newFixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
    }
    
    

    newScheduledThreadPool

    public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE,
                  DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
                  new DelayedWorkQueue());
    }
    

    newSingleThreadExecutor

    public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
    }
    

    决绝策略 如果队列满了,线程也到达最大线程数,新执行拒绝策略

    ThreadPoolExecutor.AbortPolicy()   //丢弃任务,抛出异常
    ThreadPoolExecutor.CallerRunsPolicy()  //开启线程池的线程执行任务,缺点是可能会阻塞此线程
    ThreadPoolExecutor.DiscardOldestPolicy()   //将任务队列中时间最老的任务丢弃,将新任务添加入队列
    ThreadPoolExecutor.DiscardPolicy()    //将任务丢弃不做任何操作
        
    //自定义拒绝策略
    class Reject implements RejectedExecutionHandler{
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                r.run();   
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值