Java线程 基础

任务Runnable接口

实现接口Runnable的run方法 可以被线程执行

Thread 类

start 方法 创建 指定 去调run 方法,交给jvm选择时间 和线程 去并发执行

run 方法 直接调 run方法 执行任务,不并发

thread 可以实现 runnable 接口 将 线程的启动交给别的线程

image-20211014160544627

1
2
3
getPriority() 得到优先级
setPriority()
Thread 静态常量 MIN_PRIORITY , NORM_PRIORITY , and MAX_PRIORITY ,

tips: javaFX 执行 显示 时需要将 任务 交给 主线程 Platform.runLater(Runnable r)

Thread Pools ( Executors.new)

image-20211014160935259

静态方法创建线程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Executors 工具类
Executors.newFixedThreadPool(3);
//线程数固定 一直存在,直到它被明确shutdown 。
//多的任务 在队列中等待,直到有线程可用。

Executors.newCachedThreadPool();
// 根据需要创建新线程,但在可用时将重用先前构造的线程。
// 60 秒内未使用的线程将被终止并从缓存中删除。 因此,保持空闲足够长时间的池不会消耗任何资源。





ExecutorService executor = Executors.newFixedThreadPool(3);

executor.execute(new PrintChar('a', 100));
executor.execute(new PrintChar('b', 100));
executor.execute(new PrintNum(100));

while (!executor.isTerminated()) ;

线程同步

synchronized同步方法

实例方法的情况下,锁位于调用该方法的对象上。

静态方法的情况下,锁在上。

同步代码块

与同步方法不同,同步语句必须指定提供内在锁的对象

有时你不需要同步整个方法,而是同步方法中的一部分。Java 可以对方法的一部分进行同步。

1
2
3
4
synchronized(this) { 
lastName = name;
nameCount++;
}

锁Lock和实例ReentrantLock

image-20211014162344526

1
2
3
4
5
6
7
8
9
private static Lock lock = new ReentrantLock();


lock.lock();
try { }
finally { lock.unlock(); }



条件变量Condition (lock.newCondition)

image-20211014162748069

image-20211014163041482

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static Lock lock = new ReentrantLock();

private static Condition notEmpty = lock.newCondition();
private static Condition notFull = lock.newCondition();

lock.lock();
while (queue.size() == CAPACITY) notFull.await();
//do
notEmpty.signal();
lock.unlock();

lock.lock();
while (queue.isEmpty()) notEmpty.await();
//do
notFull.signal();
lock.unlock();

wait notify notifyAll

wait() 、 notify() 和 notifyAll() 方法必须在这些方法的接收对象上的同步方法或同步块中调用。 否则,将发生 IllegalMonitorStateException。

  • 必须 先获得对象的锁 ,在 用 wait 使当前线程沉睡 ,等待别的线程 用 notify通知当前线程
  • 当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。
  • 只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Object.lock 锁住某个对象  只有调用 Object.notify 唤醒才行

//仓库存储的载体
11 private LinkedList list = new LinkedList();
12
13 //生产产品
14 public void produce(int num){
15 //同步
16 synchronized (list){
17 //仓库剩余的容量不足以存放即将要生产的数量,暂停生产
18 while(list.size()+num > MAX_SIZE){
19 System.out.println("【要生产的产品数量】:" + num + "\t【库存量】:"
20 + list.size() + "\t暂时不能执行生产任务!");
21
22 try {
23 //条件不满足,生产阻塞
24 list.wait();
25 } catch (InterruptedException e) {
26 e.printStackTrace();
27 }
28 }
29
30 for(int i=0;i<num;i++){
31 list.add(new Object());
32 }
33
34 System.out.println("【已经生产产品数】:" + num + "\t【现仓储量为】:" + list.size());
35
36 list.notifyAll();
37 }
38 }
39
40 //消费产品
41 public void consume(int num){
42 synchronized (list){
43
44 //不满足消费条件
45 while(num > list.size()){
46 System.out.println("【要消费的产品数量】:" + num + "\t【库存量】:"
47 + list.size() + "\t暂时不能执行生产任务!");
48
49 try {
50 list.wait();
51 } catch (InterruptedException e) {
52 e.printStackTrace();
53 }
54 }
55
56 //消费条件满足,开始消费
57 for(int i=0;i<num;i++){
58 list.remove();
59 }
60
61 System.out.println("【已经消费产品数】:" + num + "\t【现仓储量为】:" + list.size());
62
63 list.notifyAll();
64 }
65 }
66 }

阻塞队列BlockingQueue

image-20211014164615031

image-20211014164627707

ArrayBlockingQueue 构造方法指定 队列大小 put 时如果 队列满 则等待

ArrayBlockingQueue 和 LinkedBlockingQueue 和 PriorityBlockingQueue 在 take 时等待 队列不为空

信号量 Semaphores

指定 同时 在上面 的线程数量 +-1

image-20211014165042389

1
2
3
4
5
private static Semaphore semaphore = new Semaphore(1);


try { semaphore.acquire(); }
finally { semaphore.release(); }

线程状态

New,

Ready, ( start 之后 等待 操作系统分配时间 )

Running, ( 开始执行时,它进入运行状态 ) ( 调用 yield 回到 ready )

Blocked, ( wait join sleep )

Finished

isAlive() —–> Ready/Running/Blocked —-true

interrupt()——–> 就绪或运行—>中断标志

​ 当前被阻塞,它被唤醒并进入就绪状态,并抛出一个 java.lang.InterruptedException。

image-20211014172109583

Collections同步集合 ( list, set, map )

Collections 类提供了六个静态方法,用于将集合包装到同步版本中,

image-20211014173139924

1
2
3
4
5
6
//原理类似于
public boolean add(E o) {
synchronized (this) {
return c.add(o);
}
}

同步包装类是线程安全的,但迭代器是失败的。

要遍历一个集合,你必须这样写代码:

1
2
3
4
5
6
7
8
Set hashSet = Collections.synchronizedSet(new HashSet());

synchronized (hashSet) {
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}

并行处理 Fork/Join 框架

并行处理是使用 Fork/Join 框架实现的。

1
2
3
4
5
6
7
8
9
10
11
//分治
if (the program is small)
solve it sequentially;
else {
divide the problem into nonoverlapping subproblems;
solve the subproblems concurrently;
combine the results from subproblems to solve the whole problem;
}



image-20211014190439886

ForkJoinTask 的两个子类 RecursiveAction 和 RecursiveTask

要定义具体的任务类,您的类应该扩展 RecursiveAction 或 RecursiveTask 。

RecursiveAction 用于不返回值的任务 invokeAll()

RecursiveTask 用于确实返回值的任务。 fork() join()

你的任务类应该覆盖 compute() 方法来指定如何执行任务。

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//数组进行排序的 Arrays.sort 和 Arrays.parallelSort 方法 
//parallelSort 方法利用多个处理器来减少排序时间。
//并行流,用于并行执行流操作以加快使用多个处理器的处理速度。


//1 . 任务类 继承 RecursiveAction 重写 compute()
//2. 创建 fork/join实例
//3. 调用 实例的invoke 执行 任务

{
RecursiveAction mainTask = new SortTask(list);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(mainTask);
}









private static class SortTask extends RecursiveAction {



//11 递归调用不返回
// invokeAll(new SortTask(firstHalf), new SortTask(secondHalf));


@Override
protected void compute() {
//递归调用 左右 两半(允许 可变参数 并行计算)
//在执行主任务时,将任务拆分为子任务,并调用子任务
//使用 invokeAll 方法。 invokeAll 方法终究会返回子任务完成。 请注意,每个子任务会进一步递归地拆分为更小的任务。
//可以在池中创建和执行大量子任务。 Fork/Join 框架自动高效地执行和协调所有任务。
invokeAll(new SortTask(firstHalf), new SortTask(secondHalf));

// 合并结果
merge(firstHalf, secondHalf, list);
}



//22 拿返回值
// new Task1().fork; new Task2().fork;
// Take1().join; Take2().join;



@Override
public Integer compute() {
if (high - low < THRESHOLD) return 1;
else
{
int mid = (low + high) / 2;
RecursiveTask<Integer> left = new MaxTask(list, low, mid);//人物类
RecursiveTask<Integer> right = new MaxTask(list, mid, high);//人物类

right.fork();//执行
left.fork();//执行
return Math.max(left.join(), right.join());//拿返回值
}
}



}
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2022 ajian
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信