*** 作系统中会存在多个进程:这些进程包括系统进程、以及用户进程。
系统进程指: *** 作系统内部建立的进程。
用户进程指:用户程序建立的进程。
1.进程和进程之间不共享内存,进程是在独立的内存空间中运行的。
2.而线程则可以共享系统分配给这个进程的内存空间。
3.线程不仅能共享进程的内存,也拥有自己的内存空间,这段空间叫做线程栈,是在建立线程时由系统分配的,主要用来保存线程内部所使用的数据。
Java通过Thread类将线程所必需的功能都封装了起来。
线程执行函数就是run()方法
Thread还有一个start()方法,这个方法是建立线程,调用strat()方法后,如果线程建立成功,则程序会自动调用Thread类的run()方法。
任何继承Thread类的都可以通过调用start方法【建立】线程,如果希望运行自己编写线程的执行函数,则要覆盖Thread类的run()方法。
public class ThreadTest extends Thread { @Override public void run(){ for (int i = 0;i<=10;i++){ System.out.println(i); } } public void run2(){ for (int i = 0;i<=10;i++){ System.out.println(i+"run2............."); } } //显式无参构造 ThreadTest(){ System.out.println("创建了ThreadTest"); } public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); threadTest.start(); threadTest.run2(); } }图片下载案例
public class ThreadTestPictureDown { public void download(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("不合法的URL,下载失败"); } } }
本质上和之前的案例没什么区别,唯一有需要注意的地方是FileUtils这个工具类,能实现下载文件的功能。
public class TDownLoad extends Thread{ private String url; private String name; public TDownLoad(String url,String name){ this.url = url; this.name = name; } @Override public void run() { ThreadTestPictureDown threadTestPictureDown = new ThreadTestPictureDown(); threadTestPictureDown.download(url,name); System.out.println("下载"+name+"图片完成"); } public static void main(String[] args) { TDownLoad t1 = new TDownLoad("https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF","t1.jpg"); TDownLoad t2 = new TDownLoad("https://t7.baidu.com/it/u=4036010509,3445021118&fm=193&f=GIF","t2.jpg"); TDownLoad t3 = new TDownLoad("https://t7.baidu.com/it/u=963301259,1982396977&fm=193&f=GIF","t3.jpg"); t1.start(); t2.start(); t3.start(); } }
打印结果图片3、图片1、图片2
Thread和Runnable能够通过继承Thread类、Runnable接口实现线程类,Thread类其实也实现了Runnable接口,Thread作为实现类功能更加强大,而Runnable接口源码中只有一个run方法。但是Java中只能够实现单继承,却可以实现多个接口,因此在使用时,注意合理选择。
在继承Thread类时,如果没有为这个类命名,会自动使用默认线程名Thread-N,N代表线程建立的顺序,是一个不重复的整数。
此时可以多个代理。下面抢票小案例可以看出。
public class ThreadTest01 implements Runnable{ @Override public void run(){ for (int i = 0;i<=10;i++){ System.out.println(i); } } public void run2(){ for (int i = 0;i<=10;i++){ System.out.println(i+"run2............."); } } //显式无参构造 ThreadTest01(){ System.out.println("创建了ThreadTest"); } public static void main(String[] args) { ThreadTest01 threadTest01 = new ThreadTest01(); new Thread(threadTest01).start(); threadTest01.run2(); } }
抢票小案例
public class ThreadTest01 implements Runnable{ private int tickNums = 99; @Override public void run(){ while (true){ if (tickNums<0){ break; } System.out.println(Thread.currentThread().getName()+"--->"+tickNums--); } } //显式无参构造 ThreadTest01(){ System.out.println("创建了ThreadTest"); } public static void main(String[] args) { ThreadTest01 threadTest01 = new ThreadTest01(); //多个代理,加入名称区分 new Thread(threadTest01,"thread01").start(); new Thread(threadTest01,"thread02").start(); new Thread(threadTest01,"thread03").start(); } }
但这样是有问题的,现实情况中网络存在延迟,就可能出现负数问题。此时还没出现,下面加入线程睡眠200毫秒,模拟这种情况。
@Override public void run(){ while (true){ if (tickNums<0){ break; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"--->"+tickNums--); } }
这样在控制台打印时就会出现负数的情况。此时也算是并发问题,后续需要保证线程安全。runable接口可以共享资源,但也会出现资源抢夺的问题。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)