一个进程表示一个程序,在一个程序上可以运行多个子程序,子程序被称为线程。
进程:在一个时间段内只能完成一件事。
线程:在进程基础上划分,在同一时间段内可以比传统进程完成更多的功能。
CPU只有一个,是指在同一个时间段内可以完成多个程序,但在同一个时间点内,只能有一个程序工作。
线程与进程的区别:
多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响。
线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换负担要小。
Java的线程可以通过继承java.lang.Thread类来实现,每个线程都是通过某个Thread类对象对应的run()方法来完成操作的,run()方法称为线程体。
Java.lang为java程序默认导入包,一个类只要继承了Thread类,就表示此类实现了多线程,如果在程序中直接调用run()方法,实际上只是调用类.方法,而没有启动操作系统的支持。
class Demo extends Thread{ private String info; public Demo(String info){ this.info = info; }//多线程需要一个主体,子类要覆写Thread类中的run()方法 public void run(){ for (int i = 0;i <= 10 ;i ++ ){ System.out.println(this.info+"i = "+i); } System.out.println(""); } } public class JavaDemo127{ public static void main(String args[]){//如果此程序是一个多线程,肯定会交替运行 Demo d1 = new Demo("Thread 1: "); Demo d2 = new Demo("Thread 2: "); Demo d3 = new Demo("Thread 3: "); d1.run(); d2.run(); d3.run(); } } |
要执行多线程,则要调用public void start()方法,通过start()调用的是子类中的run()方法,启用多线程。
class Demo extends Thread{ private String info; public Demo(String info){ this.info = info; }//多线程需要一个主体,子类要覆写Thread类中的run()方法 public void run(){ for (int i = 0;i <= 10 ;i ++ ){ System.out.println(this.info+"i = "+i); } System.out.println(""); } } public class JavaDemo128{ public static void main(String args[]){//如果此程序是一个多线程,肯定会交替运行 Demo d1 = new Demo("Thread 1: "); Demo d2 = new Demo("Thread 2: "); Demo d3 = new Demo("Thread 3: "); d1.start(); d2.start(); d3.start(); } } |
由于类继承有限制,在JDK中提供了Runnable接口,也可以实现多线程,优选接口,避免类的单继承,Thread类实际上也是实现了Runable接口。
class Demo implements Runnable{ private String info; public Demo(String info){ this.info = info; } public void run(){ for (int i = 0;i <= 10 ;i ++ ){ System.out.println(this.info+"i = "+i); } System.out.println(""); } } public class JavaDemo129{ public static void main(String args[]){ Demo d1 = new Demo("Thread 1: "); Demo d2 = new Demo("Thread 2: "); Demo d3 = new Demo("Thread 3: "); Thread t1 = new Thread(d1); //Runnable接口要启动线程必须通过Thread类 Thread t2 = new Thread(d2); Thread t3 = new Thread(d3); t1.start();//通过Thread类的对象启动多线程 t2.start(); t3.start(); } } |
Thread和Runable特点:继承Thread类的多线程之间不能实现资源的共享,而实现Runable接口之后可以实现多个线程之间的资源共享。
例:10张火车票,给4个代售点销售。 Thread类的多线程:
class Demo extends Thread{ private int ticket=10; public void run(){ while (this.ticket > 0){ System.out.println("卖票:"+this.ticket--); } } } public class JavaDemo130{ public static void main(String args[]){ Demo d1 = new Demo();//准备4个售票点 Demo d2 = new Demo(); Demo d3 = new Demo(); Demo d4 = new Demo(); d1.start();//d1.start(); // //无论调用多少遍start()方法一个线程对象只能只启动一次 d2.start(); d3.start(); d4.start(); } } |
class Demo extends Thread{ private int ticket=10; public void run(){ while (this.ticket > 0){ System.out.println("卖票:"+this.ticket--); } } } public class J{ public static void main(String args[]){ //准备4个售票点 Demo d1 = new Demo(); Thread t1 = new Thread(d1); Thread t2 = new Thread(d1); Thread t3 = new Thread(d1); Thread t4 = new Thread(d1); t1.start(); //d1.start(); //无论调用多少遍start()方法一个线程对象只能只启动一次 t2.start(); t3.start(); t4.start(); } } |
Runable接口实现的多线程:
class Demo implements Runnable{ private int ticket=10; public void run(){ while (this.ticket > 0){ System.out.println("卖票:"+this.ticket--); } } } public class JavaDemo131{ public static void main(String args[]){ Demo d = new Demo();//4个售票点应该控制同一资源 Thread t1 = new Thread(d); Thread t2 = new Thread(d); Thread t3 = new Thread(d); Thread t4 = new Thread(d); t1.start();//t1.start();//线程只启动一次 t2.start(); t3.start(); t4.start(); } } |
线程启动之后要等待CUP进行调度,并不是立刻启动。
所有的线程操作就是指Thread类的操作,当前运行的线程可以指当前操作这个方法的线程。
取得当前运行的线程:public static Thread currentThread()
class Demo implements Runnable{ public void fun(){//public static Thread currentThread()方法表示取得当前运行的线程 System.out.println(Thread.currentThread()); } public void run(){ for (int i = 0;i <10 ;i++ ){ this.fun(); } } } public class JavaDemo133{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d); Thread t2 = new Thread(d); Thread t3 = new Thread(d); t1.start(); t2.start(); t3.start(); } } |
取得线程名称、设置线程名称:在Thread API中使用getName()、setName()
class Demo implements Runnable{ public void fun(){ //getName()表示取得当前线程的名字默认线程名:Thread-0 System.out.println(Thread.currentThread().getName()+"在运行..."); } public void run(){ for (int i = 0;i <10 ;i++ ){ this.fun(); } } } public class JavaDemo134{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d,"线程1"); Thread t2 = new Thread(d,"线程1"); Thread t3 = new Thread(d,"线程1"); /*通过构造方法修改线程名 t1.setName("线程1"); t2.setName("线程2"); t3.setName("线程3");*/ t1.start(); t2.start(); t3.start(); } } |
main()方法也是一个线程,之前所有的程序都是基于多线程的运行机制:在main方法中通过对象.方法调用的一切代码都是主线程。
class Demo implements Runnable{ public void fun(){ System.out.println(Thread.currentThread().getName()+"在运行..."); } public void run(){ for (int i = 0;i <10 ;i++ ){ this.fun(); } } } public class JavaDemo135{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d,"线程1"); t1.start(); for (int i = 0;i<10 ;i++ ){ d.fun();//main方法也是一个线程 } } } |
isAlive():用来检测线程是否启动而且仍然启动,结果没有固定内容,因为线程有可能优先完成,也可能在最后执行。
class Demo implements Runnable{ public void run(){ System.out.println(Thread.currentThread().getName()+"在运行..."); } } public class JavaDemo136{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d,"线程1"); System.out.println("线程启动以前:"+t1.isAlive()); t1.start(); System.out.println("线程启动以后:"+t1.isAlive()); for (int i = 0;i < 1000000000 ;i++ ){ ;//加入一个延迟 } System.out.println("线程延迟以后:"+t1.isAlive()); } } |
Public static voidsleep():用于将线程短暂休眠。sleep()需要try...catch...
class Demo implements Runnable{ public void fun(){ for(int i=0;i<10;i++){ try{ Thread.sleep(1000);//sleep()需要try...catch... }catch (Exception e){ } System.out.println(Thread.currentThread().getName()+"在运行..."); } } public void run(){ this.fun(); } } public class JavaDemo137{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d,"线程1"); Thread t2 = new Thread(d,"线程2"); t1.start(); t2.start(); } } |
Public final voidjoin():强制某一个线程运行,指一个线程必须运行完成之后其他线程才可以继续运行。需要try...catch...
class Demo implements Runnable{ public void run(){ for (int i=0;i<100 ;i++ ){ System.out.println(Thread.currentThread().getName()+"运行中....i= "+i); } } } public class JavaDemo138{ public static void main(String args[]){ Thread t = new Thread(new Demo(),"线程t"); t.start(); for (int i=0;i<100 ;i++ ){ if (i == 10){ try{ t.join();//强制运行一个线程,直到线程结束 }catch (Exception e){ } } System.out.println(Thread.currentThread().getName()+"线程运行中....i= "+i); } } } |
Public void interrupt():当一个线程运行时,另一个线程可以调用interrup()来中断它。
class Demo implements Runnable{ public void run(){ System.out.println("1、Demo --->程序进入休眠状态!!!"); try{ Thread.sleep(20000); }catch (Exception e){ System.out.println("2、Demo --->程序休眠被中断!!!"); return;//返回调用处 } System.out.println("3、Demo --->程序休眠正常退出!!!"); } } public class JavaDemo139{ public static void main(String args[]){ Thread t = new Thread(new Demo(),"线程t"); System.out.println(t.getName()+"--->线程启动"); t.start(); System.out.println("4、main--->线程休眠"); try{ Thread.sleep(2000); }catch (Exception e){ } System.out.println("5、main--->中断线程"); t.interrupt(); System.out.println("6、main--->退出线程"); } } |
Public BooleanisInterrupted():检查线程中断的状态。
public class JavaDemo140 extends Object { public static void main(String[] args) { Thread t = Thread.currentThread(); System.out.println("Point A: t.isInterrupted()=" + t.isInterrupted()); t.interrupt(); System.out.println("Point B: t.isInterrupted()=" + t.isInterrupted()); System.out.println("Point C: t.isInterrupted()=" + t.isInterrupted()); try { Thread.sleep(2000); System.out.println("was NOT interrupted"); } catch ( InterruptedException x ) { System.out.println("was interrupted"); }// 在这里因为sleep抛出了异常,所以它清除了中断标志 System.out.println("Point D: t.isInterrupted()=" + t.isInterrupted()); } } |
线程如果中断之后在休眠,则会清除标志。
线程同步:方法同步:
class Demo implements Runnable { private int ticket = 10 ; public synchronized void fun(){// 加入一个同步方法把需要同步的地方放在同步方法之中 if(this.ticket>0){//保护 try{ Thread.sleep(100) ; }catch (Exception e){ } System.out.println(Thread.currentThread().getName()+" --> 卖票:"+this.ticket--) ; } } public void run() { while(ticket>0){//保护 this.fun() ; } } }; public class JavaDemo141 { public static void main(String args[]) { Demo d = new Demo() ; Thread t1 = new Thread(d,"售票点 A") ; Thread t2 = new Thread(d,"售票点 B") ; Thread t3 = new Thread(d,"售票点 C") ; t1.start() ; t2.start() ; t3.start() ; } }; |
线程同步:同步代码块:
class Demo implements Runnable{ private int ticket = 10; public void run(){ while (this.ticket > 0){ synchronized(this){ //需要一个同步对象对当前线程同步 if (this.ticket > 0){ try{ Thread.sleep(100); }catch (Exception e){ } System.out.println(Thread.currentThread().getName()+"售票:"+ticket--); } } } } } public class JavaDemo142{ public static void main(String args[]){ Demo d = new Demo(); Thread t1 = new Thread(d,"售票点A"); Thread t2= new Thread(d,"售票点B"); Thread t3 = new Thread(d,"售票点C"); t1.start(); t2.start(); t3.start(); } } |
同步会产生死锁问题,就是在多线程中由于处理不当而造成停止运行的一种状态。模拟死锁:
class DemoA{ public synchronized void funA(DemoB db){ System.out.println("DemoA --->进入DemoA中的funA()"); db.fun2(); } public synchronized void fun2(){ System.out.println("DemoA --->public synchronized void fun2()"); } } class DemoB{ public synchronized void funB(DemoA da){ System.out.println("DemoB --->进入DemoB中的funB()"); da.fun2(); } public synchronized void fun2(){ System.out.println("DemoB --->public synchronized void fun2()"); } } class ThreadDead implements Runnable{ private DemoA da = new DemoA(); private DemoB db = new DemoB(); public ThreadDead(){ new Thread(this).start(); da.funA(db); } public void run(){ db.funB(da); } } public class JavaDemo143{ public static void main(String args[]){ new ThreadDead(); } } |
同步的经典范例:生产者和消费者
class Person{ String name; String content; } class Pro implements Runnable{ private Person per ; public Pro(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ if (i%2 == 0){ per.name = "李岩"; try{ Thread.sleep(100); }catch (Exception e){ } per.content = "作者"; }else{ per.name = "李小岩"; try{ Thread.sleep(100); }catch (Exception e){ } per.content = "天才"; } } } } class Cust implements Runnable{ private Person per ; public Cust(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ try{ Thread.sleep(100); }catch (Exception e){ } System.out.println(per.name+"--->"+per.content); } } } public class JavaDemo144{ public static void main(String args[]){ Person per = new Person(); Pro p = new Pro(per); Cust c = new Cust(per); new Thread(p).start(); new Thread(c).start(); } } |
class Person{ private String name; private String content; public synchronized void set(String name,String content){ this.name = name; try{Thread.sleep(100); }catch (Exception e){ } this.content = content; } public synchronized String get(){ return this.name+"--->"+this.content; } } class Pro implements Runnable{ private Person per ; public Pro(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ if (i%2 == 0){ per.set("李岩","作者"); }else{ per.set("李小岩","天才"); } } } } class Cust implements Runnable{ private Person per ; public Cust(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ try{ Thread.sleep(100); }catch (Exception e){ } System.out.println(per.get()); } } } public class JavaDemo145{ public static void main(String args[]){ Person per = new Person(); Pro p = new Pro(per); Cust c = new Cust(per); new Thread(p).start(); new Thread(c).start(); } } |
class Person{ private String name; private String content; private boolean flag = false; public synchronized void set(String name,String content){ //判断:如果为绿灯时表示可以设置,否则等待true flase为不可以设置 if (flag){ try{ wait(); }catch (Exception e){ } } this.name = name; try{Thread.sleep(100); }catch (Exception e){ } this.content = content; flag = true; notifyAll(); } public synchronized String get() { if(!flag){ try{ wait() ; }catch (Exception e) { } } String str = this.name+" --> "+this.content ; // 如果为红灯,则表示可以取,否则等待:false flag = false ; notifyAll() ; return str ; } } class Pro implements Runnable{ private Person per ; public Pro(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ if (i%2 == 0){ per.set("李岩","作者"); }else{ per.set("李小岩","天才"); } } } } class Cust implements Runnable{ private Person per ; public Cust(Person per){ this.per = per; } public void run(){ for (int i=0 ;i<100 ;i++ ){ try{ Thread.sleep(100); }catch (Exception e){ } System.out.println(per.get()); } } } public class JavaDemo146{ public static void main(String args[]){ Person per = new Person(); Pro p = new Pro(per); Cust c = new Cust(per); new Thread(p).start(); new Thread(c).start(); } } |
线程的等待及唤醒:
Wait():告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify为止。
Notify():唤醒wait的第一个线程。有序
notifyAll():唤醒wait中的所有线程。无序
控制线程的生命周期:
class Demo implements Runnable{ boolean flag = true; public void run(){ int i = 0; while (flag){ System.out.println("运行 i = "+i++); } } } public class JavaDemo147{ public static void main(String args[]){ Demo d = new Demo(); Thread t = new Thread(d); t.start(); try{ Thread.sleep(100) ; }catch (Exception e) { } d.flag = false; } } |