多线程总结(一)
多线程实现的五种方法
1、使用Synchronized关键字修饰方法,java对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
2、 使用Synchronized静态代码块
3、 使用局部变量方式ThreadLocal来创建一个static变量,多线程执行时会在自身工作区域创建局部变量副本
4、 使用volatile来修饰共享变量,这样每次线程需要操作变量时,从主内存拿,而不是从操作自己的工作内存的那个副本
5、 使用重入锁实现线程同步
死锁的产生是必须要满足一些特定条件
1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
线程池的submit和execute方法区别
虽然executor是线程池的顶层接口,但真正实现的接口却是:executorService
submit有返回值,而execute没有
用到返回值的例子,比如说我有很多个做validation的task,我希望所有的task执行完,然后每个task告诉我它的执行结果,是成功还是失败,如果是失败,原因是什么。然后我就可以把所有失败的原因综合起来发给调用者。
个人觉得cancel execution这个用处不大,很少有需要去取消执行的。
###submit方便Exception处理
意思就是如果你在你的task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。
代码展示区别
1 | public class RunnableTestMain { |
实现一个多线程的类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class RunnableTest implements Runnable {
private String taskName;
public RunnableTest(final String taskName) {
this.taskName = taskName;
}
public void run() {
System.out.println("Inside "+taskName);
throw new RuntimeException("RuntimeException from inside " + taskName);
}
}
Java的CountDownLatch和CyclicBarrier的理解和区别
CountDownLatch
从字面上可以看CountDown表示减法计数,Latch表示门阀的意思,当什么时候计数变成0的时候,门阀打开
表示主线程等其他所有线程执行完毕才开始执行,当计数为0的时候,下一步的动作实施者是main函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37package com.nyist.thread;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(4);
for(int i = 0; i < latch.getCount();i++){
new Thread(new MyThread(latch),"玩家"+i).start();
}
System.out.println("所有玩家都已经准备好");
latch.await();
System.out.println("开始游戏");
}
private static class MyThread implements Runnable{
private CountDownLatch latch;
public MyThread(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
try {
int randowNum = new Random().nextInt(10) + 1000;
Thread.sleep(randowNum);
System.out.println(Thread.currentThread().getName()+"已经准备好,所用时间"+randowNum);
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
CyclicBarrier
主线程不等待其他线程直接结束,而其他线程必须同时执行完一个任务去执行下一个任务之前等待其他线程执行完毕才可以执行下一个任务1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package com.nyist.thread;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
for(int i = 0; i < cyclicBarrier.getParties();i++){
new Thread(new MyThread(cyclicBarrier),"玩家"+i).start();
}
System.out.println("游戏结束!");
}
private static class MyThread implements Runnable{
private CyclicBarrier cyclicBarrier;
public MyThread(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public void run() {
for(int i = 0; i< 3;i++){
try {
int t1 = new Random().nextInt(1000) + 1000;
Thread.sleep(t1);
System.out.println(Thread.currentThread().getName()+"通过"+(i+1)+"个障碍,耗时"+t1+"毫秒");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
}
CountDownLatch和CyclicBarrier区别
两个都有让多个线程等待同步之后再去执行下一步的意思!但是呢,CountDownLatch是主线程等待其他线程,而CyclicBarrier主线程早早结束,然后其他执行完毕的线程来等待还没有执行完成的线程,最后再一起进入下一步的执行过程!