转载

JAVA多线程——并发

线程状态图:

JAVA多线程——并发

图来自 Java线程的6种状态及切换(透彻讲解)

初始、就绪、运行、等待、阻塞(synchronized)、终止。

Thread.sleep(millis)一定时间后自动恢复执行, 不释放对象锁

Object.wait()直接 释放锁 ,一直等待,知道notify()唤醒。

Thread1.join()表示运行的线程阻塞自己,等待Thread1执行完,再执行下面语句。

yield()让出cpu, 不释放对象锁 ,进入就绪态,随时可能再次运行。

只有运行态和就绪态之间涉及到CPU资源的切换。(即yield())

Thread开启的3种方式

Thread、Runnable、Callable

  • Thread
    最简单的一种,直接继承Thread,重写run方法。主类中new ThreadName().start();则进去就绪态。
  • Runnable

    • 实现Runnable接口,重写run。主类中new RunnableName().start();
    • 实现Runnable接口,重写run。主类中new Thread(new Runnable()).start();
    • Thread类还有其他重载方法,如传入ThreadGoup,Runnable初始执行接口等等,以上两个最常用。

    Thread类也是实现了Runnable接口,实际上都是调用的Runnable接口的run()方法。

  • Callable

    实现Callable接口,重写call()方法。创建FutureTask对象new FutureTask<>(CallableName);再new Thread(FutureTak).start();即可。FutureTask间接实现了Runnable和Future,所以实际调用的还是Thread(Runnable)构造方法。

    Callable接口只有一个方法V call();

Executor管理线程

  • newFixedThreadPool固定大小的线程池
  • newCachedThreadPool可扩展的
  • newScheduledThreadPool可调度的,运行一次,重复运行等
  • newSingleThreadPool单线程池
  • newWorkStealingPool窃取别的线程池的线程

使用:

ExecutorService executor = Executors.newFixedThreadPool(3);
Future<String> future = excutor.submit(Callable);//加入线程池
future.get();//获取返回值

后台线程deamon

定义:程序运行时在后台提供通用服务的线程,这种线程并不属于不可或缺的部分。后台线程运行的前提是必须有至少一个非后台线程运行。

Thread.setDeamon(ture);必须在start()前设置。

java.util.concurrent包

  • CountDownLatch

    同步多个任务,可以设置一个初值,任何在这个对象上调用wait()都将被阻塞,知道值变成0,每个任务执行完调用countDown都使值减1。

    初始值不能重置,只能一直减下去。CyclicBarrier可以重置。

  • CyclicBarrier
    用于并发任务等待(类似join),如:idm多线程下载文件,最后进行文件整理。可以重置初始值。
  • DelayedQueue
    用于延时队列(延时取出元素),队头的延迟最长。
  • PriorityBlockingQueue
    优先级阻塞队列
  • SemaPhore
    信号量,允许n个任务同时访问。

安全失败的原理

就是CopyOnWriteArrayList方法。

JAVA多线程——并发

java.util.concurrent包下面的所有的类都是安全失败的

快速失败的异常:ConcurrentModificationException

乐观锁:version、CAS(compareAndSwap)(Atomic包、ReentrankLock就是具体实现)

悲观锁:synchroinized

java.nio.*

基于缓冲的流。

主要组成:Channel,Buffer,Selector

JAVA多线程——并发

clear,flip,compact区别:

ByteBuffer中有pos、lim、cap来记录缓冲使用情况。

  • clear : position=0,limit=capacity,【清空缓冲】
  • flip : limit=postion;position=0;【读指针移动缓冲头】
  • compact : 未读完的数据,压缩到缓冲头。【压缩未读完数据】

整体流程:获取通道,分配缓冲,clear,read一次,{flip,处理读到的数据,compact,read一次}

大括号{}中表示循环执行。

void fileChannel(){
        try {
            FileInputStream fis = new FileInputStream("content.txt");
            FileChannel channel = fis.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//分配缓冲
            //position置为0,limit置为capacity
            byteBuffer.clear();     
            int read = channel.read(byteBuffer);
            System.out.println(byteBuffer);
            while (read!=-1){
            //limit置成position最后的位值,再指针position调成0
            //从头读。(position、capacity、limit)
                byteBuffer.flip();          
                while(byteBuffer.hasRemaining()){
                    System.out.print((char)byteBuffer.get());
                }
                //把未读完的数据压缩至0-position,
                //下一次从position到limit读
                byteBuffer.compact();       
                read=channel.read(byteBuffer);
            }
            channel.close();
            fis.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

fileChannel还有tryLock(),lock()和release()方法。tryLock为非阻塞式,得不到锁就立马返回

IO多路复用——selector【NIO的重点】

一个选择器管理多个Channel。

推荐优秀博客: NIO的三大组件

原文  https://segmentfault.com/a/1190000023194696
正文到此结束
Loading...