Java多线程

线程的状态

新建(New)、可运行(Runnable)、阻塞(Blocking)、无限期等待(Waiting)、有限期等待(Timed-Waiting)、死亡(Terminated)java

使用线程

  • 实现Callable接口
  • 实现Runnable接口
  • 继承Thread类

线程机制

用户线程与守护(Daemon)线程

守护线程时提供通用服务的线程(例如垃圾回收线程),优先级很低
经过Thread对象的setDaemon(boolean)方法设置守护线程与用户线程,注意此方法必须在线程对象的start方法以前调用,不然会抛出java.lang.IllegalThreadStateException异常
守护线程建立的线程默认是守护线程,用户线程同理。
守护线程是为了服务用户线程而存在的,全部用户线程结束以后,jvm就退出了,守护线程天然也结束,因此守护线程的结束时间不肯定数据库

睡眠

线程的sleep方法(静态方法),休眠当前线程,当前线程进入timed-waiting状态api

yield

线程对象的yield方法代表该线程已经完成了最重要的工做,尝试让出cpu占用,把cpu使用权让给同优先级的其余线程安全

中断

interrupt()

经过调用线程对象的interrput方法中断该线程,若是该线程处于等待/阻塞状态,会抛出java.lang.InterruptedException异常。
该方法不能中断处于I/O阻塞或synchronized阻塞的线程
线程对象的该方法被调用后,会设置阻断标志为true,经过interrupted()方法检查是否有人调用了本线程的interrupt方法多线程

interrupted()

检查是否有人调用了本线程的interrupt方法并发

中断的应用

线程池的shutdownNow方法就是经过调用全部工做线程的interrupt方法来中断工做线程jvm

线程池

https://www.cnblogs.com/darknessplus/p/10359256.htmlide

线程安全的实现方法

不可变

互斥同步

synchronized关键字与ReentrantLock

都是可重入锁
synchronized关键字由jvm实现,ReentrantLock由jdk实现
ReentrantLock提供比synchronized更高级的功能性能

  • 等待可中断
  • 公平锁
  • 选择性通知

非阻塞同步

无同步

线程本地存储

ThreadLocal类
ThreadLocal 不是用来协调多线程的,而是为同一个线程的不一样方法提供共享变量
一个线程的ThreadLocal变量在任何方法内都是可见的
线程Thread保存了ThreadLocalMap,ThreadLocalMap保存了本线程的全部ThreadLocal数据
ThreadLocal提供的方法

public T get() { }
public void set(T value) { }
public void remove() { }
protected T initialValue() { }

线程之间的协调

多线程协做解决问题时,须要对他们的执行顺序进行协调

join

调用另外一个线程对象的join方法表示本线程等待另外一个线程执行完成后再继续执行

wait、notify、notifyAll

wait、notify是Object类提供的final方法,不可重写。
经过调用某个对象的wait方法,释放本线程对该对象持有的锁,进入阻塞状态。
另外一个线程调用该对象的notify方法,唤醒该对象的锁的阻塞队列中的一个线程,notifyAll方法唤醒该对象的等待队列的全部线程。
wait期间,线程会释放锁,否则会死锁。
配合synchronized使用,再同步代码中使用。

wait与sleep的区别:

  • wait是Object方法,sleep是Thread的静态方法
  • wait会释放锁,sleep不会

生产者消费者问题:

public class Wait {

    public static void main(String[] args) throws InterruptedException {
        LinkedList<Integer> list = new LinkedList<Integer>();
        Factory factory = new Factory();
        factory.setList(list);
        factory.setMaxSize(10);
        for(int i=1;i<=10;i++)
        {
            Producer producer = new Producer();
            producer.setNum(i);
            producer.setFactory(factory);
            producer.start();

            Consumer consumer = new Consumer();
            consumer.setNum(i);
            consumer.setFactory(factory);
            consumer.start();
        }
    }
}
class Producer extends Thread{
    private AbstractFactory factory;
    private int num;

    public void setNum(int num) {
        this.num = num;
    }

    public void setFactory(AbstractFactory factory) {
        this.factory = factory;
    }

    @Override
    public void run() {
        factory.produce(num);
    }
}
class Consumer extends Thread{
    private AbstractFactory factory;
    private int num;

    public void setFactory(AbstractFactory factory) {
        this.factory = factory;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public void run() {
       factory.consume(num);
    }
}
class Factory implements AbstractFactory{
    private List<Integer> list;
    private int maxSize;

    public void setList(List<Integer> list) {
        this.list = list;
    }

    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
    }

    public void produce(int num) {
        synchronized (list)
        {
            while(num+list.size()>maxSize)
            {
                try {
                    System.out.println("仓库已满。要生产的"+num+",库存容量"+maxSize);
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            int size=list.size();
            for(int i=size;i<size+num;i++)
            {
                list.add(i);
            }
            System.out.println("生产"+num+"件,总共"+list.size()+"件");
            list.notifyAll();
        }
    }

    public void consume(int num) {
        synchronized (list)
        {
            while(list.size()-num<0)
            {
                try {
                    System.out.println("仓库已空。要消费的"+num+",库存容量"+list.size());
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            int size=list.size();
            for(int i=size-1;i>=size-num;i--)
            {
                list.remove(i);
            }
            System.out.println("消耗"+num+"件,总共"+list.size()+"件");
            list.notifyAll();
        }
    }
}
interface AbstractFactory
{
    void produce(int num);
    void consume(int num);
}

await、signal、signalAll

对应着Object的wait和notify方法,Lock也有相似的机制。
经过Lock.newCondition()方法获取一个condition对象,经过condition对象的await和signal方法进行线程同步。
在使用condition对象的await和signal方法以前必须得到重入锁,调用signal方法后最好释放重入锁。

JUC包

AQS

CountdownLatch

控制一个线程等待其余线程

public static void main(String[] args) throws InterruptedException {
        final CountDownLatch count = new CountDownLatch(10);
        for(int i=0;i<10;i++){
            new Thread(){
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    count.countDown();
                }
            }.start();
        }
        count.await();
        System.out.println("END");
    }

输出:

Thread-0
Thread-2
Thread-3
Thread-1
Thread-5
Thread-4
Thread-6
Thread-7
Thread-8
Thread-9
END

Semaphore

信号量,控制并发线程数

public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(1);
        for (int i = 0; i < 10; i++) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + "正在运行");
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(Thread.currentThread().getName() + "结束");
                        semaphore.release();
                    }
                }
            }.start();
        }
    }

输出:

Thread-5正在运行
Thread-5结束
Thread-0正在运行
Thread-0结束
Thread-3正在运行
Thread-3结束
Thread-8正在运行
Thread-8结束
Thread-6正在运行
Thread-6结束
Thread-2正在运行
Thread-2结束
Thread-7正在运行
Thread-7结束
Thread-1正在运行
Thread-1结束
Thread-4正在运行
Thread-4结束
Thread-9正在运行
Thread-9结束

其余组件

FutureTask

得到任务的返回值

BlockingQueue

阻塞队列,在线程池里有应用

乐观锁和悲观锁

悲观锁

对数据更新的冲突持保守态度,认为总会发生冲突。策略是在处理数据时加锁

乐观锁

乐观锁认为发生冲突的状况比较少,不加锁,而是在更新数据的时候检查是否发生了冲突。

乐观锁的两种实现

版本号机制

为数据库表增长版本号字段,每次更新数据版本号+1。在修改数据前获取版本号,提交修改时检查两次版本号是否一致,如不一致说明数据更新发生了冲突。

CAS

Compare And Swap
现值V、旧值A、新值B,当且仅当V==A,更新B到数据库
硬件实现的原子操做

乐观锁的缺点

ABA问题

CAS,V==A并不能说明V没有发生过改变

自旋锁开销大

CAS与synchronized使用场景

CAS适用读多写少,synchronized适用写多(冲突多)

synchronized和ReenTrantLock的区别

  • 都是可重入
  • synchronized由jvm实现,ReenTrantLock时jdk api
  • ReenTrantLock高级功能:中断等待、公平锁、选择性通知
  • 二者性能相差无几
相关文章
相关标签/搜索