这篇文章上次修改于 220 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
任务Runnable接口
实现接口Runnable的run方法 可以被线程执行
Thread 类
start 方法 创建 指定 去调run 方法,交给jvm选择时间 和线程 去并发执行
run 方法 直接调 run方法 执行任务,不并发
thread 可以实现 runnable 接口 将 线程的启动交给别的线程
getPriority() 得到优先级
setPriority()
Thread 静态常量 MIN_PRIORITY , NORM_PRIORITY , and MAX_PRIORITY ,
tips: javaFX 执行 显示 时需要将 任务 交给 主线程 Platform.runLater(Runnable r)
Thread Pools ( Executors.new)
静态方法创建线程池
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 可以对方法的一部分进行同步。
synchronized(this) {
lastName = name;
nameCount++;
}
锁Lock和实例ReentrantLock
private static Lock lock = new ReentrantLock();
lock.lock();
try { }
finally { lock.unlock(); }
条件变量Condition (lock.newCondition)
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() ,再次释放锁。
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
ArrayBlockingQueue 构造方法指定 队列大小 put 时如果 队列满 则等待
ArrayBlockingQueue 和 LinkedBlockingQueue 和 PriorityBlockingQueue 在 take 时等待 队列不为空
信号量 Semaphores
指定 同时 在上面 的线程数量 +-1
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。
Collections同步集合 ( list, set, map )
Collections 类提供了六个静态方法,用于将集合包装到同步版本中,
//原理类似于
public boolean add(E o) {
synchronized (this) {
return c.add(o);
}
}
同步包装类是线程安全的,但迭代器是失败的。
要遍历一个集合,你必须这样写代码:
Set hashSet = Collections.synchronizedSet(new HashSet());
synchronized (hashSet) {
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
并行处理 Fork/Join 框架
并行处理是使用 Fork/Join 框架实现的。
//分治
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;
}
ForkJoinTask 的两个子类 RecursiveAction 和 RecursiveTask
要定义具体的任务类,您的类应该扩展 RecursiveAction 或 RecursiveTask 。
RecursiveAction
用于不返回
值的任务 invokeAll()
RecursiveTask
用于确实返回
值的任务。 fork() join()
你的任务类应该覆盖 compute()
方法来指定如何执行任务。
//数组进行排序的 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());//拿返回值
}
}
}
没有评论