JAVA 多线程

XinyiZhang 的个人博客 记录精彩的程序人生 本文由博客端 http://blog.cathyjiarui.com 主动推送

javalogo1200x700.png

线程基础概念

线程的状态及相互转换

1.初始(NEW) -- 新创建了一个线程对象,但还没有调用 start()方法;

2.运行(RUNNABLE) -- 处于可运行状态的线程正在 JVM 中执行,但它可能正在等待来自操作系统的其他资源;

//RUNNABLE
new Thread(() -> {
    try {
        System.in.read();
    } catch (IOException e) {
	e.printStackTrace();
    }
}).start();

3.阻塞(BLOCKED) -- 线程阻塞于 synchronized 锁,等待获取 synchronized 锁的状态;

//BLOCKED
Object object = new Object();
new Thread(() -> {
    synchronized (object){
	try {
	    TimeUnit.MINUTES.sleep(5);
	} catch (InterruptedException e) {
	    e.printStackTrace();
	}
    }
}).start();
Thread.sleep(2000L);
new Thread(() -> {
    synchronized (object){
    }
}).start();

4.等待(WAITING) -- Object.wait()、join()、 LockSupport.park(),进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断);

//WAITING
Object object = new Object();
new Thread(() -> {
    synchronized (object){
	try {
	    object.wait();
	} catch (InterruptedException e) {
	    e.printStackTrace();
	}
    }
}).start();

5.超时等待(TIME_WAITING) -- Object.wait(long)、Thread.join()、LockSupport.parkNanos()、LockSupport.parkUntil,该状态不同于 WAITING,它可以在指定的时间内自行返回;

6.终止(TERMINATED) -- 表示该线程已经执行完毕;

Java 多线程

创建多线程的方式

  1. 继承 Thread 类,重写 run 方法;
  2. 实现 Runnable 接口并实现 run 方法;(实际开发中选用,java 只允许单继承 增加程序的健壮性,代码可以共享,代码跟数据独立);
  3. 匿名内部类
  4. Lambda 表达式
  5. 线程池

线程挂起及唤醒

线程的中断

线程的优先级

线程分类

锁分类

内置锁

互斥锁

自旋锁

阻塞锁

重入锁

读写锁

悲观锁

乐观锁

公平锁

非公平锁

偏向锁

独占锁

共享锁

关键字

synchronized

volatile

AbstractQueuedSynchronizer

ReentrantLock(重入锁)

非公平锁( ReentrantLock(false) )

public class ReentrantLockTest {

    public static void main(String[] args) throws InterruptedException {

        ReentrantLock lock = new ReentrantLock();

        for (int i = 1; i <= 3; i++) {
            lock.lock();
        }

        for(int i=1;i<=3;i++){
            try {

            } finally {
                lock.unlock();
            }
        }
    }
}

公平锁( ReentrantLock(true) )

public class ReentrantLockTest {

    static Lock lock = new ReentrantLock(true);

    public static void main(String[] args) throws InterruptedException {

        for(int i=0;i<5;i++){
            new Thread(new ThreadDemo(i)).start();
        }

    }

    static class ThreadDemo implements Runnable {
        Integer id;

        public ThreadDemo(Integer id) {
            this.id = id;
        }

        @Override

      public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0;i<2;i++){
                lock.lock();
                System.out.println("获得锁的线程:"+id);
                lock.unlock();
            }
        }
    }
}

响应中断( lockInterruptibly() )

public class ReentrantLockTest {
    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new ThreadDemo(lock1, lock2));//该线程先获取锁1,再获取锁2
        Thread thread1 = new Thread(new ThreadDemo(lock2, lock1));//该线程先获取锁2,再获取锁1
        thread.start();
        thread1.start();
        thread.interrupt();//是第一个线程中断
    }

    static class ThreadDemo implements Runnable {
        Lock firstLock;
        Lock secondLock;
        public ThreadDemo(Lock firstLock, Lock secondLock) {
            this.firstLock = firstLock;
            this.secondLock = secondLock;
        }
        @Override
        public void run() {
            try {
                firstLock.lockInterruptibly();
                TimeUnit.MILLISECONDS.sleep(10);//更好的触发死锁
                secondLock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                firstLock.unlock();
                secondLock.unlock();
                System.out.println(Thread.currentThread().getName()+"正常结束!");
            }
        }
    }
}

获取锁时限时等待( tryLock() )

public class ReentrantLockTest {
    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new ThreadDemo(lock1, lock2));//该线程先获取锁1,再获取锁2
        Thread thread1 = new Thread(new ThreadDemo(lock2, lock1));//该线程先获取锁2,再获取锁1
        thread.start();
        thread1.start();
    }

    static class ThreadDemo implements Runnable {
        Lock firstLock;
        Lock secondLock;
        public ThreadDemo(Lock firstLock, Lock secondLock) {
            this.firstLock = firstLock;
            this.secondLock = secondLock;
        }
        @Override
        public void run() {
            try {
                while(!lock1.tryLock()){
                    TimeUnit.MILLISECONDS.sleep(10);
                }
                while(!lock2.tryLock()){
                    lock1.unlock();
                    TimeUnit.MILLISECONDS.sleep(10);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                firstLock.unlock();
                secondLock.unlock();
                System.out.println(Thread.currentThread().getName()+"正常结束!");
            }
        }
    }
}

Condition 接口

public class ConditionTest {

    static ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();
    public static void main(String[] args) throws InterruptedException {
	//Condition接口在使用前调用ReentrantLock的lock()方法获得锁
        lock.lock();
        new Thread(new SignalThread()).start();
        System.out.println("主线程等待通知");
        try {
	    //调用Condition接口的await()释放锁
            condition.await();
        } finally {
            lock.unlock();
        }
        System.out.println("主线程恢复运行");
    }
    static class SignalThread implements Runnable {

        @Override
        public void run() {
            lock.lock();
            try {
		//调用Condition的signal()方法唤醒线程
                condition.signal();
                System.out.println("子线程通知");
            } finally {
                lock.unlock();
            }
        }
    }
}

阻塞队列的简单实现

public class MyBlockingQueue<E> {

    int size;//阻塞队列最大容量

    ReentrantLock lock = new ReentrantLock();

    LinkedList<E> list=new LinkedList<>();//队列底层实现

    Condition notFull = lock.newCondition();//队列满时的等待条件
    Condition notEmpty = lock.newCondition();//队列空时的等待条件

    public MyBlockingQueue(int size) {
        this.size = size;
    }

    public void enqueue(E e) throws InterruptedException {
        lock.lock();
        try {
            while (list.size() ==size)//队列已满,在notFull条件上等待
                notFull.await();
            list.add(e);//入队:加入链表末尾
            System.out.println("入队:" +e);
            notEmpty.signal(); //通知在notEmpty条件上等待的线程
        } finally {
            lock.unlock();
        }
    }

    public E dequeue() throws InterruptedException {
        E e;
        lock.lock();
        try {
            while (list.size() == 0)//队列为空,在notEmpty条件上等待
                notEmpty.await();
            e = list.removeFirst();//出队:移除链表首元素
            System.out.println("出队:"+e);
            notFull.signal();//通知在notFull条件上等待的线程
            return e;
        } finally {
            lock.unlock();
        }
    }
}

StampedLock

特点

优点

缺点

原理

注意点

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2812 引用 • 8043 回帖 • 749 关注

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...