个人线程记录

1. 并发和并行 ThreadFactory

​ 并行:同一时刻,多个程序同时执行(几个cpu运行几个任务)

​ 并发:同一时间段,多个程序交替执行(计算机)

​ java中的多线程,是并发执行的 ,多个程序交替执行(感觉不到)

2. 进程和线程

​ 进程:电脑正在执行的一个程序

​ 线程:进程中的多个执行功能,(执行单元)

3. 线程调度

​ 多线程执行cpu的调度方式

​ 1.分时调度,每个线程执行相同的时间

​ 2.抢占式调度,线程都有优先级,优先执行优先级高的线程,如果优先级相同,则随机执行

4. 线程的创建

​ Thread(java.lang.Thread)

​ java虚拟机允许并发的运行多个执行线程

(1)第一种 Thread

​ extends Thread 重写run()方法

​ 创建对象调用start()方法,在start()方法内部调用run方法,不用自己调用如果只是调用 run()那么只是普通的调用,是顺序执行的,重写run()方法是为了写自己特有的内容

​ 栈 main方法 xxx.start() xxx.start() 每个start()都开辟一块空间两个空间相互独立,互 不影响 getName() 用于获取线程的名字 从Thread0开始

  public Thread(Runnable target,String name)  分配一个带有指定目标新的线程对象并                                               指定名字
  public static Thread currentThread()返回对当前正在执行的线程对象的引用,当前正在运行的线程类,可以为main线程
(2)第二种Runnable

   class MyRunnable implements Runnable{...}

        MyRunnable mr = new MyRunnable();
        Thread t = new Thread(mr, "小强");
Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。
而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

1. 适合多个相同的程序代码的线程去共享同一个资源。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

-----Runnable只是一个接口,这个接口中只有一个run()方法,

 public class Thread implements Runnable{
           ................
        }
  只有Thread及其子类才可以使用.start()方法开启线程
(3)第三种Callable

interface Callable

1. Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而           Runnable的    run()函数不能将结果返回给客户程序
2. Future就是对于具体的Runnable或者Callable任务的执行结果进行
(4)一种结合的

​ 他把Runnable和Futrue结合起来了

--FutureTask是一个RunnableFuture<V>
public class FutureTask<V> implements RunnableFuture<V>
--RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口
interface RunnableFuture<V> extends Runnable, Future<V>
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
 ---------------------------------------------------------------
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    runnable最终会被转化成Callable通过RunnableAdapter适配器,RunnableAdapter是一个Executors中的一个内部类

FutureTaslk还可以包装Runnable和Callable, 由构造函数注入依赖。

因此FutureTask是Future也是Runnable,又是包装了的Callable( 如果是Runnable最终也会被转换为Callable )。

5.线程同步机制

(1)同步代码块
Object lock = new Object();
synchronized(同步锁lock){
    需要同步操作的代码
 }
(2) 同步方法

使用synchronized修饰的方法,就叫做同步方法

同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

  1. 锁对象 可以是任意类型。
  2. 多个线程对象 要使用同一把锁。
public synchronized void method(){
  可能会产生线程安全问题的代码
}
(3) 锁机制

定义:

java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。

lock锁也叫同步锁,加锁和释放锁都写好方法了

Lock lock = new ReentrantLock(); //创建一个所对象
public void lock()  //加同步锁
public void unlock()//释放同步锁

6. 线程状态

(1)线程的几种状态

​ (1)新建(new):线程刚被创建,但是并未启动。还没调用start方法

​ (2)可运行(Runnable):线程可以在java虚拟机中运行的状态

​ (3)阻塞(Blocked):尝试获取锁对象,但是锁却被占用,进入阻塞,当有锁时,进入可运行状态

​ (4)无限等待(waiting):等待另一个线程唤醒,它不能自己醒来,等待令一个线程调用notify或者notifyAll才能被唤醒

​ (5)计时等待(Timed Waiting): 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态 将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait

​ (6)终止(Teminated): 因为run方法正常退出而死亡

(2)等待和唤醒

​ Obejct中的方法

  wait()  //让当前线程进入到等待状态 此方法必须锁对象调用.
  notify()  //唤醒当前锁对象上等待状态的线程 此方法必须锁对象调用
https://www.cnblogs.com/xiaoxi/p/6637740.html
public class ThreadA extends Thread{
    
    public ThreadA(String name){
        super(name);
    }
    
    public void run(){
        synchronized(this){
            System.out.println(Thread.currentThread().getName()+" call notify()");
             // 唤醒当前的wait线程
            notify();
        }
    }
}
***********************************************************************
 public class WaitTest {
    
    public static void main(String[] args){
        
        ThreadA t1 = new ThreadA("t1");
        
        synchronized(t1){
            try{
                 // 启动“线程t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();
                
                // 主线程等待t1通过notify()唤醒。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();

                System.out.println(Thread.currentThread().getName()+" continue");

            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
运行结果:
main start t1
main wait()
t1 call notify()
main continue

7. 线程池

1.概念

​ 是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源

2.使用线程池的好处
1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存
3.线程池接口
1. java.util.concurrent.Executor  
线程池的*接口,但是他并不是真正的线程池,他只是一个线程的执行工具
里面只有一个方法 void execute(Runnable command);
2. java.util.concurrent.ExecutorService
ExecutorService 继承了Executor
4.线程池的创建
3. java.util.concurrent.Executors
     在线程工厂里提供了一些静态工厂,生成常用的线程池,可以使用Executors来创建线程池
     ExecutorService newFixedThreadPool(int nThreads)//放的是最大的线程池数量
     <T> Future<T> submit(Callable<T> task); //线程的执行
     shutdown()//关闭线程池
4. java.util.concurrent.Future<V>接口:用来记录线程任务执行完毕后产生的结果。
     get()方法是一个阻塞方法,他在着等待线程返回的结果
5.使用步骤
1. 创建线程池对象。
2. 创建Runnable接口子类对象。(task)
3. 提交Runnable接口子类对象。(take task)
4. 关闭线程池(一般不做)。
上一篇:多线程ExecutorService 的理解与使用


下一篇:java – RestTemplate应该是静态全局声明的吗?