进程与线程
进程是执行程序静态代码的过程。
一个进程可以包含多个线程。
微观来看,多线程并不是同时执行多个线程,而是JVM虚拟机使CPU在多个线程之间的快速切换;
宏观来看,当切换的速度够快,不同的线程就感觉就是在同时执行。
Java默认的的主线程是main,当在main中创建的线程就称之为其他线程。
线程的五种状态
Java实现多线程的两种方式
1. 继承Thread类
执行Main方法时,JVM启动一个进程,主线程在调用main()方法时被创建直接变为可运行状态(无需调用start),其他线程的start方法被调用后,线程变为可运行状态。主线程和其他线程的执行顺序与CPU分配有关。(乱序,每次执行顺序都不同)
class Thread1 extends Thread
{
int i=10;
@Override
public void run()
{
for(;i>0;)
{
System.out.printf("Thread1"+"\n");
i--;
}
}
}
class Thread2 extends Thread
{
int j=10;
@Override
public void run()
{
for(;j>0;)
{
System.out.printf("Thread2"+"\n");
j--;
}
}
}
public class Main
{
public static void main(String []args)
{
Thread1 day = new Thread1();
Thread2 night = new Thread2();
day.start();
night.start();
for(int k=0;k<10;k++)
{
System.out.printf("main thread..."+"\n");
}
}
}
2.实现Runnable接口
本质上还是通过Thread创建新线程。
class MyRunnable1 implements Runnable
{
int i=10;
public void run()
{
for(;i>0;)
{
System.out.printf("day"+"\n");
i--;
}
}
}
class MyRunnable2 implements Runnable
{
int j=10;
public void run()
{
for(;j>0;)
{
System.out.printf("night"+"\n");
j--;
}
}
}
public class Main
{
public static void main(String []args)
{
Runnable runnable1 = new MyRunnable1();
Runnable runnable2 = new MyRunnable2();
Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);
thread1.start();
thread2.start();
for(int k=0;k<10;k++)
{
System.out.printf("main thread..."+"\n");
}
}
}
3.使用Callable和Future接口创建线程
当子线程的call方法未执行完成之前,get方法会一直处于阻塞状态,直到call方法执行完才能取到返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable1 implements Callable {
String i = "Thread1";
@Override
public Object call() throws Exception {
for(int k=0;k<10;k++)
{
System.out.println(Thread.currentThread().getName()+" i的值:"+ i);
}
return i; //call方法可以有返回值
}
}
class MyCallable2 implements Callable {
String i = "Thread2";
@Override
public Object call() throws Exception {
for(int k=0;k<10;k++)
{
System.out.println(Thread.currentThread().getName()+" i的值:"+ i);
}
return i; //call方法可以有返回值
}
}
public class Main {
public static void main(String[] args) {
Callable callable1 = new MyCallable1();
Callable callable2 = new MyCallable2();
FutureTask task1 = new FutureTask(callable1);
FutureTask task2 = new FutureTask(callable2);
new Thread(task1,"子线程One").start();
new Thread(task2,"子线程Two").start();
try
{
System.out.println("子线程返回值:"+task1.get() + "\n");
System.out.println("子线程返回值:"+task2.get() + "\n");
} catch (Exception e)
{
e.printStackTrace();
}
for(int k=0;k<10;k++)
{
System.out.println("主线程。。。。" + "\n");
}
}
}
Thread VS Runnable
继承Thread时可以直接实例化对象然后调用start方法。而对于继承Runnable接口时,需要通过Thread转换才能调用start方法。
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源【代码复用】
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类