多线程最简单的使用

几乎每种操作系统都支持进程的概念 ―― 进程就是在某种程度上相互隔离的、独立运行的程序。

线程化是允许多个活动共存于一个进程中的工具。大多数现代的操作系统都支持线程,而且线程的概念以各种形式已存在了好多年。Java 是第一个在语言本身中显式地包含线程的主流编程语言,它没有把线程化看作是底层操作系统的工具。

有时候,线程也称作轻量级进程。就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其它每个进程应有的状态。

    进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。尽管这让线程之间共享信息变得更容易,但你必须小心,确保它们不会妨碍同一进程里的其它线程。

为什么使用线程?

使用线程的一些原因是它们可以帮助:

使 UI 响应更快

利用多处理器系统

简化建模

执行异步或后台处理

对于web主要是,异步处理,服务器应用程序从远程来源(如套接字)获取输入。当读取套接字时,如果当前没有可用数据,那么对 SocketInputStream.read() 的调用将会阻塞,直到有可用数据为止。

因为是阻塞IO,所以一个线程只可以处理一个IO套接字,(当然,程序可以轮询套接字,查看是否有可用数据,但通常不会使用这种做法,因为会影响性能。NIO不存在这个问题)

但是,如果创建了一个线程来读取套接字,那么当这个线程等待套接字中的输入时,主线程就可以执行其它任务。通过可以创建多个线程,这样就可以同时读取多个套接字。使用线程等待套接字的代码也比轮询更简单、更不易出错。

当多个线程访问同一数据项(如静态字段、可全局访问对象的实例字段或共享集合)时,需要确保它们协调了对数据的访问,这样它们都可以看到数据的一致视图,而且相互不会干扰另一方的更改。

Java 语言提供了两个关键字:synchronized 和 volatile。

synchronized关键字用法(原理http://www.importnew.com/29031.html

一 原子性(互斥性):实现多线程的同步机制,使得锁内代码的运行必需先获得对应的锁,运行完后自动释放对应的锁。

二 内存可见性:在同一锁情况下,synchronized锁内代码保证变量的可见性。

三 可重入性:当一个线程获取一个对象的锁,再次请求该对象的锁时是可以再次获取该对象的锁的。

如果在synchronized锁内发生异常,锁会被释放。

总结:

(1)synchronized方法 与 synchronized(this) 代码块 锁定的都是当前对象,不同的只是同步代码的范围

(2)synchronized (非this对象x) 将对象x本身作为“对象监视器”:

a、多个线程同时执行 synchronized(x) 代码块,呈现同步效果。

b、当其他线程同时执行对象x里面的 synchronized方法时,呈现同步效果。

c、当其他线程同时执行对象x里面的 synchronized(this)方法时,呈现同步效果。

(3)静态synchronized方法 与 synchronized(calss)代码块 锁定的都是Class锁。Class 锁与 对象锁 不是同一个锁,两者同时使用情况可能呈异步效果。

(4)尽量不使用 synchronized(string),是因为string的实际锁为string的常量池对象,多个值相同的string对象可能持有同一个锁。

volatile关键字用法

一 内存可见性:保证变量的可见性,线程在每次使用变量的时候,都会读取变量修改后的最的值。

二 不保证原子性。

java线程简介(https://www.ibm.com/developerworks/cn/education/java/j-threads/j-threads.html

每个 Java 程序都至少有一个线程 ― 主线程。当一个 Java 程序启动时,JVM 会创建主线程,并在该线程中调用程序的 main()方法。

JVM 还创建了其它线程,通常都看不到它们 ― 例如,与垃圾收集、对象终止和其它 JVM 内务处理任务相关的线程。其它工具也创建线程,如 AWT(抽象窗口工具箱(Abstract Windowing Toolkit))或 Swing UI 工具箱、servlet 容器、应用程序服务器和 RMI(远程方法调用(Remote Method Invocation))。

创建线程

Thread t = new Thread(() -> System.out.println("Thread lambda")); 

t.start();

使用一个线程最简单的方法,传入一个Runnable。(如开头上)

或者是继承thread类。


但是从Java5之后就基本上使用线程池来代替直接创建线程。

利用Executors类提供了4种不同的线程池:newCachedThreadPool, newFixedThreadPool, newScheduledThreadPool, newSingleThreadExecutor。

newCachedThreadPool

创建一个可缓存的无界线程池,该方法无参数。当线程池中的线程空闲时间超过60s则会自动回收该线程,当任务超过线程池的线程数则创建新线程。线程池的大小上限为Integer.MAX_VALUE,可看做是无限大。(SynchronousQueue实现队列)

newFixedThreadPool

创建一个固定大小的线程池,该方法可指定线程池的固定大小,对于超出的线程会在LinkedBlockingQueue队列中等待。(LinkedBlockingQueue实现队列)

newSingleThreadExecutor

创建一个只有线程的线程池,该方法无参数,所有任务都保存队列LinkedBlockingQueue中,等待唯一的单线程来执行任务,并保证所有任务按照指定顺序(FIFO或优先级)执行。

这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去(LinkedBlockingQueue实现队列)

newScheduledThreadPool

创建一个可定时执行或周期执行任务的线程池,该方法可指定线程池的核心线程个数。

concurrent包下常用类

Doug Lea主刀

AQS是concurrent包的基石(AbstractQueuedSynchronizer)

https://www.cnblogs.com/waterystone/p/4920797.html

Callable接口和Future

 Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

<T> Future<T> submit(Callable<T> task) :

CompletionService

如果想Executor提交了一组计算任务,并且希望在计算完成后获得结果,那么可以保留与每个任务关联的Future,然后反复使用get方法,同事将参数timeout指定为0,从而通过轮询来判断任务是否完成。这种方法虽然可行,但却有些繁琐。幸运的是,还有一种更好的方法:CompletionService。CompletionService将Executor和BlockingQueue的功能融合在一起。你可以将Callable任务提交给它来执行,然后使用类似于队列操作的take和poll等方法来获得已完成的结果,而这些结果会在完成时被封装为Future。ExecutorCompletionService实现了CompletionService,并将计算部分委托到一个Executor。代码示例如下:


intcoreNum = Runtime.getRuntime().availableProcessors();

ExecutorService executor = Executors.newFixedThreadPool(coreNum);

CompletionService<Object> completionService = newExecutorCompletionService<Object>(executor);

for(inti=0;i<coreNum;i++)

{

    completionService.submit( newCallable<Object>(){

        @Override

        publicObject call() throwsException

        {

            returnThread.currentThread().getName();

        }});

}

for(inti=0;i<coreNum;i++)

{

    try

    {

        Future<Object> future = completionService.take();

        System.out.println(future.get());

    }

    catch(InterruptedException | ExecutionException e)

    {

        e.printStackTrace();

    }

}

Atomic系列-原子变量类


主要使用cas(compareAndSet)+volatile变量实现


直接赋值的原子操作

需要类似于实现和之前的值进行比较(例如自增)


内部是一个循环,使用unsafe中的本地方法,实现cas操作,不适用于竞争十分激烈的场景。


(CAS彻底讲解https://www.cnblogs.com/Mainz/p/3546347.html

主要使用java中的unsafe实现CAS)

ConcurrentHashMap (https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/index.html

可以高并发的map,使用分段锁,不同于hashtable。

自己使用CAS实现增长。

或者使用guava提供的AtomicLongMap。

对访问的url计数,非线程安全,具体urlhttp://www.importnew.com/26035.html

CopyOnWriteArrayList

一看名字就知道写时复制新数组,读的时候直接使用,使用于写少读多的情况。

CountDownLatch

强调的是一个线程等待多个线程完成某件事,只能用一次,无法重置;

比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行

CyclicBarrier

强调的是多个线程互相等待完成,才去做某个事情,可以重置。

CyclicBarrier,让一组线程到达一个同步点后再一起继续运行,在其中任意一个线程未达到同步点,其他到达的线程均会被阻塞。

CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.

而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.

CyclicBarrier和CountDownLatch区别

http://scau-fly.iteye.com/blog/1955165

线程池https://fangjian0423.github.io/2016/03/22/java-threadpool-analysis/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容

  • 林炳文Evankaka原创作品。转载自http://blog.csdn.net/evankaka 本文主要讲了ja...
    ccq_inori阅读 654评论 0 4
  • 多线程的简单理解和使用 1,基础概念 1.1 进程和线程 根本区别: 进程:进程是操作系统资源分配的基本单位。 线...
    偏偏爱吃梨阅读 238评论 0 4
  • 一.线程安全性 线程安全是建立在对于对象状态访问操作进行管理,特别是对共享的与可变的状态的访问 解释下上面的话: ...
    黄大大吃不胖阅读 842评论 0 3
  • 多线程 1.悲观锁和乐观锁 http://www.importnew.com/21037.html 悲观锁悲观锁,...
    bigfish1129阅读 371评论 0 0
  • 有云的地方,就是天下 有人的地方,就是江湖! 人在江湖,身不由己! 谁也 不能独善其身! 只有浮沉随浪 活在当下记...
    f0c53644bf62阅读 434评论 0 0