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修饰的方法,就叫做同步方法
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
- 锁对象 可以是任意类型。
- 多个线程对象 要使用同一把锁。
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. 关闭线程池(一般不做)。