多线程允许同时完成多个任务。
创建线程的四种方式
1.jdk1.5之前,继承Thread类或实现Runnable接口
2.jdk1.5之后,实现Callable接口以及线程池
1.创建线程:继承Thread
继承Thread类,要重写run()方法
class Thread1 extends Thread{
@Override
public void run(){
for(int i = 0 ;i<20;i++){//自定义
System.out.print("0");
}
}
}
再写一个类
class Thread2 extends Thread{
@Override
public void run(){
for(int i = 0 ;i<20;i++){//数字
System.out.print("1");
}
}
}
测试:
创建线程对象,并就绪
@Test
public void Test1(){
Thread1 thread1 = new Thread1();//创建了一个线程
thread1.start();//thread1就绪,随时等待cpu的调度
Thread2 thread2 = new Thread2();//又创建了一个线程
thread2.start();//thread2就绪,随时等待cpu的调度
for(int i = 0 ;i<20;i++){//数字
System.out.print("*");
}
}
这里创建了两个线程对象,并且在主线程中也写了一个输出循环。
运行结果:
每次运行结果是不同的。
2.创建线程:实现Runnable接口
3.创建线程:实现Callable接口
Callable和Runnable不同点:
1.实现Callable接口需要重写call方法,实现Runnable接口需要重写run方法
2.call方法有返回值,run方法没有返回值
3.call方法可以抛出异常,run方法不能
创建步骤:
1.写一个类实现Callable接口
class CallableA implements Callable{
public Object call() throws Exception {
return null;
}
}
2.创建线程对象
①Callable对象
因为不能new Thread(callable),所以要借助FutureTask
②Futuretask对象
new Thread(futuretask)是可以的。
public static void main(String[] args) {
CallableTest2 callable = new CallableTest2();//创建外部类对象
CallableA callableA = callable.new CallableA();//注意创建内部类对象要先创建外部类对象
FutureTask task =new FutureTask(callableA);
Thread threadA = new Thread(task);
}
3.start()就绪
public static void main(String[] args) {
CallableTest2 callable = new CallableTest2();
CallableA callableA = callable.new CallableA();//注意创建内部类对象要先创建外部类对象
FutureTask task =new FutureTask(callableA);
Thread threadA = new Thread(task);
threadA.start();
}
其他:
task.get()可以返回call()的返回值。
如果线程没有就绪,是不会执行get的。
测试:
public class CallableTest2 {
class CallableA implements Callable{//内部类
public Object call() throws Exception {
return "reture";
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
CallableTest2 callable = new CallableTest2();
CallableA callableA = callable.new CallableA();//注意创建内部类对象要先创建外部类对象
FutureTask task =new FutureTask(callableA);
System.out.println(task.get());
}
}
结果:
如果线程就绪以后再获取call的返回值,是可以的。
public class CallableTest2 {
class CallableA implements Callable{//内部类
public Object call() throws Exception {
return "reture";
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
CallableTest2 callable = new CallableTest2();
CallableA callableA = callable.new CallableA();//注意创建内部类对象要先创建外部类对象
FutureTask task =new FutureTask(callableA);
Thread thread = new Thread(task);
thread.start();
System.out.println(task.get());
}
}
结果:
提供一个完整的匿名类构造的线程
public class CallableTest {
public static void main(String[] args) {
Callable callable = new Callable(){
public Object call() throws Exception {
System.out.println("call()");
return "return";
}
};
FutureTask futuretask = new FutureTask(callable);
Thread thread = new Thread(futuretask);
thread.setName("线程A");
thread.start();
try {
System.out.print(futuretask.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.创建线程:线程池
为什么要引入线程池?
1.减少线程创建和销毁的次数,每条线程都可以被重复利用,执行多个任务
2.避免内存消耗,防止服务器频繁的创建和销毁,造成过多的压力导致服务器崩溃
3.可以对线程管理调度(控制最大并发数)避免过多的资源争抢
4.可以定时执行任务
线程池原理:讲得好.
public ThreadPoolExecutor(int corePoolSize,//核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//线程的保持时间,(如果太久没有分配任务就销毁了)
TimeUnit unit,//空闲线程保持时间的单位
BlockingQueue<Runnable> workQueue) {//线程的等待队列
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
并行和并发
并发:同一时间,同一cpu执行多个线程任务
并行:同一时间,多个cpu执行多个线程任务