进程与线程:
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,线程依托于进程存在。比如在Windows系统中,一个运行的exe就是一个进程
线程指的是进程中的一个执行流程,,一个进程中可以运行很多线程,进程中的多个线程间共享进程的内存
比如:打开qq,在qq中可以聊天,可以刷动态,可以留言,每一个操作都是一个进程
线程的创建:
- 继承Thread类
class MyThreadB1 extends Thread{
private int ticket = 10;
@Override
public void run(){
while (ticket > 0){
System.out.println("剩余"+--this.ticket+"张");
}
}
}
//启动线程
new MyThreadB1().start();
new MyThreadB1().start();
new MyThreadB1().start();
在单线程下是问题的,但是当有多个Thread对象时就会出现一票多卖的问题,这是因为三个对象都是自己的10张票
- 实现Runnable接口
class MyThreadB implements Runnable{
private int ticket = 5;
private String title ;
// @Override
public void run() {
while (ticket > 0){
System.out.println("spare ticket"+--this.ticket);
}
}
}
MyThreadB mythreadb = new MyThreadB();
new Thread(mythreadb).start();
new Thread(mythreadb).start();
此时,MyThreadB实现了Runnable接口,就是一个Runnable对象,将Runnable对象传入Thread构造方法中,创建线程,调用start()方法,启动线程
但种种方式不能解决run方法有返回值的情况,所以有下面的方式
- 实现Callable接口
class MyThreadB implements Callable<String> {
private int ticket = 10;
@Override
public String call() throws Exception{
while(ticket > 0){
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+
"spare ticket "+--this.ticket);
}
return "empty!";
}
Callable<String> callable = new MyThreadB();
FutureTask<String> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
Thread thread1 = new Thread(task);
-
实现Callable接口这种方式也不能直接的启动线程,因为Callable接口中也没有start方法,但这里有一个类叫FutureTask,这个类是Runnable接口的间接实现子类,而且该类的构造方法可以将Callable对象变成FutureTask对象,因此FutureTask这个类可以将Callable与Runnable联系起来,就可以利用Thread的构造方法再次创建新的线程,进而使用start方法启动线程
-
要取得call()方法的返回值这里要使用的方法时Future接口的get()方法,FutureTask是Future接口的子类,所以可以用FutureTask对象去调用get()方法取得call()方法的返回值
线程的启动:
调用start(),而不是调用run方法,run方法中是想让自己的线程做的任务的具体实现,实际上线程的启动还是用Thread类的start方法,并且这个方法只能被调用一次
调用start方法进而调用start0方法,这时会产生一个线程,然后线程处于就绪态,当该线程被分配CPU后,JVM会自动调运行run方法
总结:
继承Thread类和实现Runnable接口的区别:
1.继承Thread类有单继承的缺陷,扩展性不好,Runnable就没有这个缺陷
2.继承Thread资源难以实现共享,Runnable接口的方式可将一个Runnable对象传入多个Thread中,很容易资源共享
3.继承Thread类,业务实现与线程启动耦合,而继承Runnable接口将业务事项与线程启动解耦,便于维护
线程中的代理模式
使用接口实现多线程是一个典型的代理模式
一个接口:Runnable或Callable接口
一个真实业务类:继承接口的真实业务类,覆写接口中的run()或call()
一个代理类:Thread类,自定义线程类的启动等操作都要靠它