进程,是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发。
线程,是进程的子任务,是CPU调度和分派的基本单位,实现了进程内部的并发。
线程在进程下运行。
进程之间不会影响。
不同进程很难共享数据。
同进程下的线程数据很容易共享。
进程使用内存地址可以限定用量。
继承Thread类
重写run方法:
public class Mythread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"执行第"+i+"次..");
}
}
}
测试:
import java.util.*;
class Test{
public static void main(String[] args) {
//创建线程
Mythread t1=new Mythread();
Mythread t2=new Mythread();
Mythread t3=new Mythread();
//设置线程名
t1.setName("线程1");
t2.setName("线程2");
t3.setName("线程3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
控制台输出片段:
线程交替执行,而并非顺序执行,说明它们使用同一资源,属于同一进程。
实现Runnable接口
并重写run方法:
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try{
//sleep会发生异常要显示处理
Thread.sleep(20);//暂停20毫秒
}catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行了"+i+"次..");
}
}
}
sleep():
使当前正在执行的线程暂停指定的毫秒数,也就是进入休眠的状态。
需要注意的是,sleep 的时候要对异常进行处理。
测试:
import java.util.*;
class Test{
public static void main(String[] args) {
//创建Runnable
MyRunnable myRunnable = new MyRunnable();
//创建线程,设置名称
Thread t1=new Thread(myRunnable,"线程1");
Thread t2=new Thread(myRunnable,"线程2");
Thread t3=new Thread(myRunnable,"线程3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
控制台输出片段:
join()等待这个线程执行完才会轮到后续线程得到cpu的执行权,使用这个也要抛出异常。
测试:
import java.util.*;
class Test{
public static void main(String[] args) {
//创建Runnable
MyRunnable myRunnable = new MyRunnable();
//创建线程,设置名称
Thread t1=new Thread(myRunnable,"线程1");
Thread t2=new Thread(myRunnable,"线程2");
Thread t3=new Thread(myRunnable,"线程3");
//启动线程
t1.start();
try {
t1.join(); //等待t1执行完才会轮到t2,t3抢
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
}
}
控制台输出片段:
setDaemon():
将此线程标记为守护线程,准确来说,就是服务其他的线程,像 Java 中的垃圾回收线程,就是典型的守护线程。
import java.util.*;
class Test{
public static void main(String[] args) {
//创建Runnable
MyRunnable myRunnable = new MyRunnable();
//创建线程,设置名称
Thread t1=new Thread(myRunnable,"线程1");
Thread t2=new Thread(myRunnable,"线程2");
Thread t3=new Thread(myRunnable,"线程3");
t1.setDaemon(true);
t2.setDaemon(true);
//启动线程
t1.start();
t2.start();
t3.start();
}
}
控制台输出片段:
如果其他线程都执行完毕,main 方法(主线程)也执行完毕,JVM 就会退出,也就是停止运行。如果 JVM 都停止运行了,守护线程自然也就停止了。
实现Runable接口比继承Thread方法好,避免了Java单继承的局限性;适合多个相同的程序代码去处理同一资源的情况,把线程、代码和数据有效的分离,更符合面向对象的设计思想。
实现Callable接口
重写call()方法,这种方式可以通过FutureTask获取任务执行的返回值 :
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class CallerTask implements Callable<String > {
@Override
public String call() throws Exception {
return "正在运行..";
}
public static void main(String[] args) {
//创建异步任务
FutureTask<String>task=new FutureTask<>(new CallerTask());
//启动线程
new Thread(task).start();
try{
//等待执行完成,返回获取结果
String res=task.get();
System.out.println(res);
}catch (Exception e) {
e.printStackTrace();
}
}
}
控制台输出:
重写run方法原因:
封装被线程执行的代码。
run()和start()区别:
run():封装线程执行的代码,直接调用相当于调用普通方法。
start():启动线程,然后由JVM 调用此线程的run() 方法。
Java线程周期: