任务Runnable接口

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

Thread 类

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

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

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

image-20211014160544627

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

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

Thread Pools ( Executors.new)

image-20211014160935259

静态方法创建线程池

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

image-20211014162344526

private static Lock lock = new ReentrantLock();


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


条件变量Condition (lock.newCondition)

image-20211014162748069

image-20211014163041482

    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

image-20211014164615031

image-20211014164627707

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

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

信号量 Semaphores

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

image-20211014165042389

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

//原理类似于
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;
}


image-20211014190439886

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());//拿返回值 
            }
        }
         
        
 
 }