thread相关

多线程进行同一个操作,可以使用synchronize同步,或者使用锁lock,也可以使用Atomic原子类。Atomic内部使用自旋锁和CAS进行操作,并发量大了之后,会导致多次自旋,唯一制约Atomic性能的就是高并发。

为了应对这种情况,Java8之后引进了LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator,这些采用了分段加锁。比如1000,LongAdder可以分为100,100,。。。,100。多个并发过来了可以分到多个cell里面去独立操作,当要取值的时候,就把100,99,。。。80,100等加起来,就是LongAdder的值了。ConcurrentHashMap等,也是这个思想,多个cell进行独立操作。

LongAdder关键方法就是add和sum

验证不了!!!!!!!!SOS fuck bitch!!!!!!!

那本并发,封面为房子的书

 

1、问:threadLocal?

     曰:为每一个线程提供共享变量的一个副本。线程的所有操作都在副本上进行,不影响原始值。每一个线程来了,都会在map里面将线程id为key,变量值为value保存起来,每次操作都需要经过这个map。

    操作方法有new ThradLocal,这里需要赋值

   ThreadLocal<Integer> local = new ThreadLocal<Integer>(){
    public Integer initialValue() {
        return 0;
    }
};

     操作的时候先local.get(),还可以local.set()。

2、问:Runnable与Callable?

     曰:Runnable接口是没有值返回的Thread方法也是,Callable接口有值返回,所以可以将callable模式用于Feature。Feature可以有done?get,cancel等操作方法。

3、问:进程间的通信方法?

      曰:进程间的通信,一般叫做Linux的进程间通信(那就与某个语言没啥卵关系了),可以看做是不同系统之间的通信。1、我们用的已有的数据同步方法是“共享文件”,A系统写入到文件F中,B系统来读取。2、使用消息队列,想象比如kafka、RockMQ。3、使用信号量。4、管道(或命名管道)。

      管道:在linux中,一切皆文件,管道也就是使用一款共享的内存空间,并且只能是单工通信。匿名管道,用于相关进程(父子进程)之间的通信,创建方式为int pipe();命名管道,用于同一个无关进程之间的通信,创建方式为int mkfifo(),还需要打开 open(),打开之后的性能就和匿名管道一样的了。随着进程结束而结束。

      消息队列:与管道的区别是,双工通信。比如队尾读队首写。

      共享内存:与管道有什么区别?管道的数据是从用户态内存拷贝到内核内存,再进行操作。而共享内存少了用户态内存与内核内存两次拷贝的操作,是当前速度最快的通信方式。kafka的速度之所以这么快,也有用到零拷贝的理念。

      信号量:进程间的互斥与同步。只允许信号量存在的情况下进行操作。P操作:-1;V操作:+1。

      套接字:上面都是同一个机器,如果不同机器之间的通信,可以使用套接字。

      文件:按照数据交换的目的,很明显文件可以用来异步操作啊。

4、问:线程创建的方法

      曰:

BASE:  ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

此RejectedHandler也可以自己实现,比如写入数据库后续进行补偿操作等。

生成方法:

 

 

线程操作有start, run, sleep, interrupt, join, stop(过时),suspend、resume ??

  1. 在线程A中创建线程B,调用B.join,则A会阻塞,B会进行。如果join有参数则在参数时间到点后,继续进行A的操作;(join没有参数则直到B执行完再继续A);如果B没有结束而A调用了interrupt,也继续进行A的操作。但是,所有的上述情况,B没有结束都会继续进行。B并没有被kill。
  2. 银行账号加减的例子,操作100次时间太短,看不出效果。操作n次,得到的答案每次都不同,说明在某个线程执行期间,有值写入主内存,否则,只在工作内存操作不会影响其他线程的值。
  3. CopyOnWriteArrayList、CopyOnWriteArraySet两者,当有iterator选定之后,可以进行元素的修改。但iterator读取的是修改之前的内容,修改之后的在copy的里面。再次iterator读取则是新的内容。可能是同步copy的到了origin里面了。于此相反的,普通ArrayList在iterator之后再进行move、add等操作可以成功,但iterator读取会报错,此时iterator已经失效。
  4. Exchanger用于交换两个线程的数据。这两个线程需要通过一个共同的exchanger进行关联。
  5. Futrue用法。1创建类继承Callable接口,创建Futrue对象,创建Thread对象。2创建线程池,用线程池submit方法调用Runnable实现类。

synchronize、violate、ReentrentLock原理

1、synchronize:

      一个对象的组成为 对象头、 实例数据、填充数据。对象头中有许多内容,其中有个硬指针指向一个ObjectMonitor,每一个对象实例都有一个monitor。monitore里面包含了状态、排队线程、占用线程等,当一个线程锁住这个对象,就会把状态、使用对象相应的标记。其他线程过来,判断自己占用不了就进入排队队列(公平原理)。这样就实现了锁。

2、violate:

      1、汇编编译的时候,会在被violate修饰的字段前增加一个lock标识,当这个字段被改动了,并且有lock标识,就会强制从缓存写入内存,而不用等到随机的时候被cpu写入。

      2、CPU会循环的扫描,或许是扫描被violate修饰的字段,如果发现字段被改动了(地址变了),就会将缓存中的数据置为失效。当需要使用数据的时候,而又为失效则向内存中去拉取新数据。

3、reentrntlock

    继承使用AQS,abstractQueueSnynchronider,里面有字段,CAS的时候就是操作这个公共的字段用来获得锁。可以设置时间与中断。

 

引用类型:

 

 

《JAVA并发实践》

  1. 线程安全集合
  1. map:HashTable、SynchronizedMap、ConcurrentMap
  2. List:Vector、CopyOnWriteArrayList/CopyOnWriteArraySet、SynchronizedList/SynchroinzedSet
  3. Queue:BlockQueue、ConcurrentLinkedQueue

 

  1. 同步synchronizedXX,并发concurrent XX
  2. 同步容器Collections.synchronizedXXX工厂创建了HashTable、Vector
  3. 并发容器ConcurrentXXX

 

ConcurrentHashMap等并发容器的实现原理呢????

 

《实战java高并发程序设计》

1、3.1节有很多工具类,可以细细再看一遍。

 

协程

进程:一个实例就是一个进程。

线程:创建、可运行、运行中、阻塞、销毁

协程:由代码控制,不由操作系统控制,没有线程间的切换、线程间状态的变化等。适合于IO操作:如果线程在等待IO,那么就将CPU让出来给其他协程用,这里CPU是主动让出来的,并没有线程间的切换;缺点是让出来之后没有被别的协程还回来,就会很尴尬了。可以看出,其是单线程的东西,不可以利用多核操作等。

Java原生语法没有实现协程,有些开源框架Kilim实现了但是不流行。Python、Lua、Go有实现。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值