线程启动
线程的启动只能调用start方法,在java中,在执行一个线程之所以会调用run方法,是Thread类中有一个start0方法中有一个变量started初值为false,在调用start0()方法后,started才置为true,而start0()方法是c语言实现的,所以java中创建一个线程本质是c语言实现,而在C语言创建一个线程之后就直接调用了run方法,所以java中的在使用线程时,如果直接调用run方法,是不会开启线程的,只是调用了一个普通方法,必须调用start()方法启动线程,
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
1.继承Thread类,然后覆写run方法(run方法为线程任务)
class My extends Thread{
private int count=20;
@Override
public void run() { //线程主体业务
while(count>0) {
System.out.println(count--);
}
}
}
以买票为例,该方法在创建线程时需要创建三个对象,只能自己卖自己手中的票,不容易完成多线程对一个对象的组合任务.(可以完成对同一对象的操作,x单例)
2.实现Runna接口,然后覆写run方法;
class My1 implements Runnable{
private String title;
private int count=20;
public My1(String title) {
this.title = title;
}
@Override
public void run() {
while(count>0) {
System.out.println(String.valueOf(Thread.currentThread())+count--);
}
}
}
Java中Thread类本身也实现了Runnable接口,与用户自定义的线程类共同组成代理设计模式。其中Thread类实现辅助操作,包括线程的资源调度等任务;自定义线程类完成真实业务,Runnable接口被继承后,实例化一个对象,传入Thread类的构造方法,即可以创建一个或多个线程.
3.实现Callable接口,然后覆写call<v>方法
class My3 implements Callable<>{
private int ticket=2000;
@Override
public Object call() throws Exception {
while (ticket>0) {
System.out.println("当前线程为"+Thread.currentThread().getName()+"----"+ticket--);
Thread.sleep(2000);
}
return "没票了";
}
}
在实例化My3后,通过构造方法传入FutureTask<>类中实例一个FutureTask对象,再通过构造方法传入Thread类中实例化一个线程,该方式的主要应用是FutureTask类是Runnable的一个孙子类,而FutureTask类可以接收一个实现Callable接口的对象,通过构造方法就可创建一个线程,
该方法的优势是可以接受一个返回值,通过future接口i的get()方法获取
继承Thread类与实现Runnable区别?
I.继承Thread类有单继承局限,相对而言实现Runnbale接口更加灵活,并且Thread类本身也实现了Runnable辅助真实线程类。
II.实现Runnable接口可以更好的实现程序共享的概念(Thread类也可以,但需要涉及单例,稍微麻烦些)
4.线程池
核心线程池 corePoolSize
最大线程池 maxiumPoolSize
阻塞队列
- ArrayBlockingQueue:基于数组的有界阻塞队列
- LinkedBlockingQueue:基于链表的无界阻塞队列,内置线程池FixedThreadPool,SingleThreadPool都采用此队列
- SychronousQueue:一个不存储元素的无界阻塞队列,一个元素的插入操作必须要等待同时有一个元素的删除操作,否则插入操作就一直阻塞。内置线程池CachedThreadPool就采用此队列,
- PriorityBlockingQueue:基于优先级的阻塞队列
固定大小的线程池
Exectors.newFixedThreadPool(int nThread)
内部源码实现
return new ThreadPoolExecutor(nThreads, nThreads, //核心线程池 最大线程池
0L, TimeUnit.MILLISECONDS, //线程活动保持时间单位
new LinkedBlockingQueue<Runnable>()); //拒绝策略
单线程池
Exectors.newSingleThreadExecutor()
内部源码实现
return new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
缓存线程池
Executors.newCachedThreadPool()
内部源码实现
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
定时调度池
Executors.newScheduledThreadPool(int nThreads);
内部源码实现
return new ScheduledThreadPoolExecutor(corePoolSize);
自定义线程池
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize, //最大线程池大小
long keepAliveTime, //线程活动保持的时间
TimeUnit unit, //线程活动保持的时间单位
BlockingQueue<Runnable> workQueue, //阻塞队列
RejectedExecutionHandler handler); //饱和策略