多线程
一.进程的基本概念: 操作系统中一个程序的执行周期称为一个进程。
二.线程的基本概念: 一个程序同时执行多个任务,通常一个任务就是一个线程(一个进程中包含多个线程)。
三.进程与线程的区别:
1.每个进程拥有自己的一整套变量,是操作系统中资源分配的最小单位,线程依托进程存在,多个线程共享数据,共享变量使得线程之间通信比进程之间通信更有效,更方便。
2.创建,撤销一个线程比启动一个新进程开销要小的多(线程轻量级)
3.没有进程就没有线程,进程一旦终结终结,其内在线程也会全部撤销。
四.高并发:访问的线程量非常高,就会带来高并发问题,则服务器内存不够用,无法处理新的请求。可采取扩容,分布式解决(程序复杂度增加)
五.多线程的实现:
1.继承Thread类实现多线程
java.lang.Thread是一个线程操作的核心类(JDK1.0提供)。新建一个线程简单的方法就是直接继承Thread类,而后覆写该类中 的run()方法(就相当于主类中的main方法)
package bit.mult;
class MyThread extends Thread{ //线程主题类
private int ticket=10;
public void run(){ //所有线程从此处开始执行
while (ticket>0){
System.out.println(Thread.currentThread().getName()+"还剩下"+this.ticket--+"票");
}
}
}
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
MyThread myThread3 = new MyThread();
// myThread1.run();//与线程启动无关
// myThread2.run();
// myThread3.run();
myThread1.start( );
// myThread1.start( );//每个线程对象只能启动一次
myThread2.start( );
myThread3.start( );
}
}
当线程的实例化对象调用run方法时,只是在执行普通方法,与多线程无关。启动多线程的方式是调用Thread类中的Start()方法。
启动多线程:public synchronized void start()此方法会自动调用线程的run()方法。
Java中多线程创建的调用流程如图(通过源码分析):
a. 首先检查状态是否为0(线程默认状态为0,表示为启动),一个线程的start()只能调用一次。
b. 然后我们看到了在start()方法中调用了start0()方法,而这个方法是一个只声明而未实现的方法同时使用 native关键字进行定义。通过start0()真正启动线程。
private native void start0(),native指的是调用本机的原生系统函数。
c…Thread 类有个 registerNatives 本地方法,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),start()等,所有操作本地线程的本地方法都是有它注册的
d.Jvm调用start()0方法进行资源分配调度,准备好资源启动线程后回调run()方法来执行线程的具体任务。Java底层已经写死了,所以并不能直接调用启动线程。
2.Runnable()接口实现多线程
Thread类的核心功能是进行线程的启动。如果一个类为了实现多线程直接去继承Thread类就会有单继承局限。在 java中又提供有另外一种实现模式:Runnable接口。
package bit.mult;
class MyThread1 implements Runnable{
private int ticket=10;
public void run(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"还剩下"+this.ticket--+"票");
}
}
}
public class RunableTest {
public static void main(String[] args) throws InterruptedException {
MyThread1 mt=new MyThread1();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
MyThread类继承的不再是Thread类而实现了Runnable接口,虽然解决了 单继承局限问题,但是没有start()方法被继承了。那么此时就需要Thread类提供的构造方法。
a.Thread类提供的构造方法:
public Thread(Runnable target),可以接收Runnable接口对象 ,多线程的启动永远都是Thread类的tart()方法.
b.Thread与RUnnable的区别
Runnable实现多线程要比继承Thread类要好,因为可以避免但继承局限。 Thread类是Runnable接口的子类,那么Thread类一定覆写了Runnable接口的run()方法.使用Runnable接口实现多线程程序类可以更好的描述资源共享。
c.Java中多线程的处理就是一个典型的代理模式,其中Thread类完成资源调度,系统分配辅助线程业务,自定义的线程类负责真是业务实现。
public class Thread implements Runnable (辅助业务)
public class Mythread implements Runnable (真是业务)
使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念(并不是说Thread不能)
3.Callable接口实现多线程
从JDK1.5开始追加了新的开发包:java.uti.concurrent。这个开发包主要是进行高并发编程使用的,包含很多在高 并发操作中会使用的类。在这个包里定义有一个新的接口Callable。Runnable中的run()方法没有返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线 程。(唯一一个有返回值的线程实现方式)
package bit.mult;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread2 implements Callable<String> {
private int ticket=1000;
public String call()throws Exception{
while(ticket>0){
System.out.println(Thread.currentThread().getName()+"还剩下"+this.ticket--+"票");
}
return "票买完了";
}
}
public class CallableTest {
public static void main(String[] args) throws InterruptedException,ExecutionException {
FutureTask<String> task=new FutureTask<>(new MyThread2());
new Thread(task).start();
new Thread(task).start();
new Thread(task).start();
System.out.println(task.get());
}
}
不管任何情况,如果要想启动多线程只有Thread类中的start()方法