进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。
线程是一条执行路径,是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。
① 顺序执行:即程序从上往下一步一步的执行
② 并发执行:指两个或多个事件在同一个时间段内执行
③ 并行执行:指两个或多个事件在同一时刻同时执行
继承Thread类后要重写Thread类的run()方法,然后调用start()方法开启线程
public class TestThread1 extends Thread{ public static void main(String[] args){ EatThread eatThread= new EatThread(); DrinkThread drinkThread= new DrinkThread(); eatThread.start(); drinkThread.start();}} class EatThread extends Thread{ @Override public void run(){ System.out.println("开始吃饭?...\t" + new Date()); try{ Thread.sleep(5000);} catch(InterruptedException e){ e.printStackTrace();} System.out.println("结束吃饭?...\t" + new Date());}} class DrinkThread extends Thread{ @Override public void run(){ System.out.println("开始喝酒?...\t" + new Date()); try{ Thread.sleep(5000);} catch(InterruptedException e){ e.printStackTrace();} System.out.println("结束喝酒?...\t" + new Date());}}
此时的运行结果为:
当把主函数(即主线程)改为run()方法开启线程:
public class TestThread1 extends Thread{ public static void main(String[] args){ EatThread eatThread= new EatThread(); DrinkThread drinkThread= new DrinkThread(); eatThread.run(); drinkThread.run();}}
此时的运行结果为:
造成区别的原因时:当使用start()方法开启线程时,各线程是并发执行的,当使用run()方法开启线程时,各线程是顺序执行的。
与继承Thread类方法类似,实现Runnable接口后要重写run()方法,然后使用Thread类来包装调用start()方法开启线程
public class TestThread2 implements Runnable{ @Override public void run(){ System.out.println("开始吃饭?...\t" + new Date()); try{ Thread.sleep(5000);} catch(InterruptedException e){ e.printStackTrace();} System.out.println("结束吃饭?...\t" + new Date());} public static void main(String[] args){ TestThread2 t1= new TestThread2(); new Thread(t1).start(); Thread thread= new Thread(t1); //对同一对象进行多线程从操作 thread.start();}}
运行结果为:
注意:newThread(t1).start();和Threadthread=newThread(t1);thread.start();这两种写法效果是一样的第一种方法继承Thread类,Thread类也实现了Runnable接口第二种方法实现Runnable接口,类似创建一个代理工具类推荐使用实现Runnable接口的方法实现多线程,可以避免Java单线程的限制线程开启不一定立即执行,由CPU调度执行
① 实现Callable接口,需要返回值类型
② 重写call()方法,需要抛出异常
③ 创建目标对象 : TestThread3 testThread3 = new TestThread3()
④ 创建执行服务 : ExecutorService ser = Executors.newFixedThreadPool(2)
⑤ 提交执行 : Future r1 = ser.submit(testThread3)
⑥ 获取结果 : boolean rst1 = r1.get();
⑦ 关闭服务 : ser.shutdownNow();
public class TestThread3 implements Callable<Boolean>{ //①实现Callable接口,需要返回值类型 private String name; public TestThread3(String name){ this.name= name;} @Override public Boolean call() throws Exception{ //②重写call()方法,需要抛出异常 if(name.equals("张三")){ System.out.println("欢迎"+name);returntrue;}returnfalse;} public static void main(String[] args) throws ExecutionException, InterruptedException{ //③创建目标对象 TestThread3 t1= new TestThread3("张三"); TestThread3 t2= new TestThread3("李四"); //④创建执行服务 ExecutorService ser= Executors.newFixedThreadPool(2); //⑤提交执行 Future<Boolean> r1= ser.submit(t1); Future<Boolean> r2= ser.submit(t2); //⑥获取结果 boolean rst1= r1.get(); boolean rst2= r2.get(); System.out.println(rst1); System.out.println(rst2); //⑦关闭服务 ser.shutdownNow();}}
运行结果:
public class Race implements Runnable{ private static String winner; @Override public void run(){for(int i= 1; i<= 100; i++){ // 模拟兔子休息 if(Thread.currentThread().getName().equals("兔子")&& i%10==0){ try{ Thread.sleep(100);} catch(InterruptedException e){ e.printStackTrace();}} boolean flag= isGameOver(i); // 如果比赛结束,终止程序if(flag){break;} // Thread.currentThread()获取当前线程 // Thread.currentThread().getName()获取当前线程名字 System.out.print(Thread.currentThread().getName()+"-->跑了"+i+"步"+"\t"); if(i%5==0) System.out.println();}} // 判断是否有胜利者 public boolean isGameOver(int step){if(winner!=null){returntrue;}else{if(step>=100){ winner= Thread.currentThread().getName(); System.out.println("winner is "+winner);returntrue;}}returnfalse;} public static void main(String[] args){ Race race= new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start();}}
结果:
参考:https://blog.csdn.net/vbirdbest/article/details/81282163.