线程总结
来源:互联网 发布:淘宝幸运大抽奖在哪 编辑:程序博客网 时间:2024/05/17 02:05
想走的远,那么你基础一定要好。别以为这些不是东西。未来能走多远,要看基础
1,两种开启线程方法:子类,Runnable接口。
2,定时器Timer,在新的线程里面定时的去做任务(TimerTask接口),设定和运行
3,线程安全:同步,也就是一些代码只能有一个线程进去,另外的线程想进去,必须等这个线程出来现。
synchronized(对象的锁){},可以修饰代码块,方法,静态方法
synchronized(this){要保护的代码},这里的锁是this,其实可以是什么都行的。在内存的位置是一样的就可以同步了。
块:锁是什么自己写
方法:锁是this
静态方法:锁是类,字节码来的
4,线程通信和互斥:我们想在线程1 在工作的时候,线程2 不要去干预,等线程一工作累了,就告诉线程2 ,线程2 来工作。
这样我们就要用到中间类,new 成final 就可以通信了,之后又同步这个类的方法,只让一个线程进。在这个类加一个判断成员变量就简单多了。通过中间类来完成通信。不是线程管。
5,绑定线程数据:new 一个Map,这样就可以用线程对象多key ,那么拿值的时候就会不同了,这就是绑定数据。线程结束就删除对应的一条数据就好。
6,绑定线程数据:ThreadLocal,这个对象相当一个map,set 值就会和线程关联了,只管加入数据。绑定那个数据ThreadLocal 管理。如果想绑定多个数据,就封装一下。要保证ThreadLocal 是唯一的。
7,多个线程访问同一个共享数据,原理:保证数据对象是一个。
- 将共享数据和操作方法封装在一个对象中,然后将这个对象传递个Runnable
对象(线程要运行的代码就在这个对象里面),这样就容易实现数据的互斥和通信。最好就加上同步。 - 利用内部类访问外部成员:把要处理的数据当作类的属性,处理方法封装好,记得同步,把Runnable
继承成内部类,那么run 方法就可以访问了。
8,线程池ThreadPool:这个人,是管理线程去做任务的,做任务的中介吧,如果人家有任务(Runnable )就给这个线程池,给完就可以回去了,中介是有工厂或人力的(线程Thread),看看谁有空,有空就叫去做任务,如果全部都在忙,那么这些任务就会在队列里面排队,是异步处理的。做网站服务器类似的就会用到。
- ThreadPool
线程池 - ExecutorService threadPool = Executors.newFixedThreadPool(3);
固定的工人,就是固定的线程 - ExecutorService threadPool = Executors.newCachedThreadPool();
有缓冲的,有多少任务就请多少工人 - ExecutorService threadPool = Executors.newSingleThreadExecutor();
单个,解决线程死掉怎么救活 - 任务 Runnable
- threadPool.execute(new Runnable(){要做的任务});
这个方法在主线程调用,加入任务的。 - 工具类
Executors
9,线程返回结果Future:当一个线程结束之后就会返回一个结果给我们。
- 在线程池用submit()提交任务,这个时候任务是Callable
,类似Runnable,运行函数为 call() 有返回结果的。 - Future future =threadPool.submit(new Callable() {call(){...}};
- 之后再调用 future.get()拿到返回结果的。但不知道什么时候有返回结果,感觉没有什么用咯,还不如自己做任务,你帮我做任务,还要我看着。
10,提交多个任务CompletionService :new 的时候要传进线程池,也是用submit()提交任务。用completion.task().get();拿到返回的结果,一次拿一个,
11,java5中的锁Lock : 就是同步,进入一段代码的时候,锁上,在出来的时候,开锁,这样就不怕的被打断了。
- Lock lock = new ReentrantLock();
//Lock 是接口,要new 其子类,Ctrl + T 一下就知道了。 - lock.lock();
//上锁 - try{......}finally{lock.unlock();} //开锁,要try/finally
12,读写锁ReadWriteLock : 可以上读或写的锁,读与读不互斥,读与写互斥,写与写互斥。
- rw.readLock().lock();
- rw.readLock().unlock();
- rw.writeLock().lock();
- rw.writeLock().unlock();
13,线程交换工作:就是你一下,我一下的工作,这个思想是怎么样呢。不是自己工作就wait(),自己做完了就notify(),叫醒别人。
- 在通信的中,共享的数据封装在相对线程是外部的,有了一个唯一的数据对象data。
- data有两个方法,分别给不同的线程调用m1()和m2();这两个方法会加Lock的。
- 一开始是线程一调用m1(),在线程机制中,每一个分配的时间是由CPU控制的,不能设置,那么现在是线程一工作,就要用状态变量标识bShouldSub,
- 当线程一工作完了,就唤醒线程二,但本应该到线程二工作了,但CPU还不急让线程二工作,时间还是给了线程一,这个时候就应该让线程一wait(),这样线程二就可以工作了。
- 重复上面的过程,就是可以,你一下,我一下的工作了。
- 完成这个,完成上面的通信,是在锁住的时候通信的,就是Lock里面的通信Condition,Lock.Condition
- 生成锁,lock = new ReentrantLock();
- 拿到这个锁的通信,Condition condition =
lock. newCondition(); - 用condition.await()
代替 this.wait(); - 用condition.signal(); 代替
this.notity(); , 同一个signal(), 只能叫醒用同一个对象await() 的对象。 - 这样就可以了。称为:多个Condition通信,可以很多个Condition
- 从两个封装中更加能体现面向对象的思想。用Condition可以实现诸塞队列。
14,灯的互斥Semaphore:信号 vt. 用信号联络 vi. 发信号,这个人是管理工作的人数,只有有灯的线程才能去工作,不然就wait()
- sp.acquire();
获得灯,如果没有灯就等,等,可以做排队用。有多少 队 ,就有多少灯 - sp.release();
做完任务就还灯。
15,线程集合一起行动:CyclicBarrier,在new 的时候就会告诉这个人,我们又多少个线程要去工作,如果线程调用这个类的await() 方法,说明到达了集合地点,那么要等够一开始设置的线程数量才能一起出发,这个等待是自己动开始的,只要人数够了,就可以行动。
- final
CyclicBarrier cb = new CyclicBarrier(3); - cb.await();// 一定要等够线程调用这个方法才能走下去。
16,计数器:CountDownLatch , 给我看清楚了,这个是计数器,不是计时器,是用来算数字的,一开始设置有多少个数,一次减去1 ,直到零,如果有线程用这个对象来await(), 那么就可以开始往下走。同一对象原则。互动对象原则
- 应用1 :设置计数为1 ,有一个准备时间,到时间减1 开始行动,就像起跑线上的。
- 应用2 :设置计数为总人数 n,每一个人做完工作就减1 ,当全部人做完工作,刚好减为 0 ,就可以去统计什么的,就像都跑到了终点。
- final CountDownLatch cdOrder = new CountDownLatch(1);
- final CountDownLatch cdAnswer = new CountDownLatch(3);
- cdOrder.await();
- cdOrder.countDown();
- 一对多,多对一
17,线程交换数据:Exchanger,连个线程交换数据,谁先到交换地点谁就等一下,调用了一个方法exchange(data), 就是到达了,当两个人都到了的时候就交换,之后就向下走了。可以换不同的数据
- final Exchanger exchanger = new Exchanger();
- Ex data2 = (Ex)exchanger.exchange(data1);
18,阻塞队列:BlockkingQueue,想知道怎么用就看API去,可以和线程池结合使用。
- 放满之后就在等待,等有人拿走了才能放进去。
19,并发集合: ConcurrentSkipListMap等等,要用就是查,我这里只是讲几个。
- 之前的集合对线程是不安全的。读的时候就不要写,写的时候就不要读。就想lock
一样,有异常这些东西的。只是原本Collection 的毛病。 - CopyOnWriteArrayList
这个类在写的时候会Copy 一份,就不会有事,
20,同步队列:SynchronousQueue,也是一个阻塞队列,这个队列是,当有人来读的时候才插入数据。如果有多个人来读数据,就插进去,看谁抢的快,谁就拿呗。
问题:可以不可以,主线程调用线程1 下载数据,主线程在做自己的事情,当线程1 下载完数据之后主线程就拿到下载后的数据输出。就是没有等待的时间。以上讲的都是异步线程同步通信的。
线程要做的东西:
- 做任务:
- 线程池最好,把任务一丢就行了。任务是Runnable
- 阻塞队列也行,自己new
Thread,任务是什么都行,如果想线程多次拿队列的东西,就 while(true){...} - 排队消费:有线程,队列,灯
- 只有一盏灯,只有拿到灯的才能消费。
- 用同步队列,只有有人来拿数据才插入数据
- 用new
产生线程,用来消费
注意:
- 线程池的工作是做任务,只管做完,在做完的时候也可以返回结果,但这样的结果没有什么用,和通信有很大的差别,通信可以一做一下,我做一下,但线程池,你给任务,我就一下子去做完。
看完帮忙评论一下,一起进步嘛。
0 0
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- 线程总结
- [笔记]Python
- 优先队列(priority_queue)
- spring aop中的propagation的7种配置的意思
- 正则表达式中的贪婪非贪婪
- android中RecyclerView的使用
- 线程总结
- python进阶学习---> django框架解析 --->领悟编程语言共性与特性【后续详解】
- Hadoop2.6.0运行mapreduce之Uber模式验证
- mycat 黑匣子
- C++使用typedef用法小结
- smtp服务器和pop3服务器是什么
- HTTP协议——处理状态和返回状态码含义
- HADOOP的本地库(NATIVE LIBRARIES)介绍
- 导出所有DB2存储过程的四种方法