概念:
1-继承Thread类创建线程类
2-通过Runable接口创建线程类
3- 通过Callable和FutureTask创建线程
a. 创建Callable接口的实现类,并实现call()方法;
b. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callback对象的call()方法的返回值;
c. 使用FutureTask对象作为Thread对象的target创建并启动新线程;
d. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
4-通过线程池创建线程
为什么要用start()来启动线程,而不是run()?
1-java应用程序的main函数是一个线程,是被JVM启动的时候调用,线程的名字叫main
2-实现一个线程,必须创建Thread实例,override run方法,并且调用start方法
3-在JVM启动后,实际上有多个线程,但是至少有一个非守护线程
4-当你调用一个线程start方法的时候,此时至少有两个线程,一个是调用你的线程(比如main方法调用的,就是main线程),
还有一个执行run方法的线程
5-线程的生命周期分为new,runnable,running,block,terminated.
多线程场景
银行叫号的机器(很多个)
runnable采用的什么设计模式?
-策略模式
算法和业务逻辑分开
threadGroup
1-创建线程对象Thread,默认有一个线程名,以Thread-开头,从0开始计数
构造函数 Thread()
名称如下:
Thread-0
Thread-1
Thread-2
2-如果在构造Thread的时候没有传递Runnable或者没有复写Thread的run方法,该Thread将不会调用任何东西,如果传递了Runnable接口
的实例,或者复写了Thread的run方法,则会执行该方法的逻辑单元(逻辑代码)
3-如果构造线程对象时未传入ThreadGroup,Thread会默认获取父线程的ThreadGroup作为该线程的ThreadGroup,此时子线程和父线程将会
在同一个threadGroup中
构造函数如下:
Thread()
Thread(Runnable target)
Thread(Runnable target,String name)
Thread(String name)
Thread(String group,Runnable target,String name,long stackSize)
4-构造Thread的时候传入stacksize代表着该线程占用的stack大小,如果没有指定stacksize的大小,默认是0,0代表着会忽略该参数,
该参数会被JNI函数去使用
需要注意:该参数有一些平台有效,在有些平台无效
5- join方法
join
6-检查线程死锁
7-锁的类别
-this:
多个方法都使用synchronized关键词修饰,或在方法中指定使用this时,共用一个this锁,也就是说,同一时间,使用了this的所有方法会变成串型执行。(定义的成员变量当做锁参数,传在synchronized中也同理)
-class:
如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是2中不同的锁。
类锁对该类的所有对象都能起作用,而对象锁不能。
8-线程通讯
例子:生产者消费者
wait和sleep的区别:
-sleep是Thread的,wait是Object的
-sleep不会释放锁,wait会释放锁
-sleep可以不定义同步代码块,wait必须加同步
-sleep不需要被唤醒,wait必须被唤醒(设置自动唤醒时间除外)