定义+创建+启动
创建线程的第一种方式:继承Thread类 public class Test{ public static void main(String[] args){ Thread thread=new Process(); thread.start(); for(int i=0;i<3;i++) System.out.println("ooo"); } } class Process extends Thread{ public void run() { for(int i=0;i<5;i++) System.out.println("haha"); } }2. 创建线程的第二种方式:实现Runnable接口
public class Test{ public static void main(String[] args){ Thread thread=new Thread(new Process()); thread.start(); for(int i=0;i<3;i++) System.out.println("ooo"); } } class Process implements Runnable{ public void run(){ for(int i=0;i<5;i++) System.out.println("haha"); } }腾出CPU给其他的线程 1、
public class Test{ public static void main(String[] args){ Thread t1=new Thread(new Process()); t1.start(); } } class Process implements Runnable{ public void run(){ for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } public class Test{ public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(new Process()); t1.setName("t1"); t1.start(); for(int i=0;i<20;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); Thread.sleep(500);//阻塞的是当前线程 } } }//main方法可以抛出异常 class Process implements Runnable{ public void run(){ for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } }//run方法为重写Thread类中的run方法,Thread类中的run方法不抛出异常,因此重写的方法不能抛出更多的异常 } public class Test{ public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(new Process()); t1.setName("t1"); t1.start(); t1.sleep(5000);//相当于Thread.sleep(5000); System.out.println("Hello world!"); } } class Process implements Runnable{ public void run(){ for(int i=0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); } System.out.println("线程结束"); } }2、
//线程正在休眠,打断其休眠 public class Test{ public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(new Process()); t1.setName("t1"); t1.start(); Thread.sleep(5000); t1.interrupt();//是通过抛出InterruptedException异常来实现的,try...catch语句结束 } }//main方法可以抛出异常 class Process implements Runnable{ public void run(){ try{ Thread.sleep(10000); }catch(InterruptedException e){ e.printStackTrace(); } for(int i=0;i<5;i++) System.out.println(Thread.currentThread().getName()+"--->"+i); }//run方法为重写Thread类中的run方法,Thread类中的run方法不抛出异常,因此重写的方法不能抛出更多的异常 }3、
//如何正确的更好的终止一个正在执行的线程 public class Test{ public static void main(String[] args) throws InterruptedException { Process process =new Process(); Thread t1=new Thread(process); t1.setName("t1"); t1.start(); Thread.sleep(5000); process.run=false; } } class Process implements Runnable{ boolean run=true; public void run(){ for(int i=0;i<1000;i++) { if(run) { System.out.println(Thread.currentThread().getName()+"--->"+i); } } System.out.println("线程结束"); } }合并后变为单线程,只能一个线程执行完后,另一个线程才能执行
public class Test{ public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(new Process()); t1.setName("t1"); t1.start(); t1.join(); for(int i=0;i<20;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); } } } class Process implements Runnable{ public void run(){ for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); } } }同一时间只能有一个线程执行上述代码。将需要同步的代码放到synchronized(共享对象){…}中,构成同步语句块
//演示使用线程同步机制的取款例子,多线程同时对同一个账户进行取款操作,使用线程同步机制保证数据安全 public class Test{ public static void main(String[] args) { Account account =new Account("Jack", 5000.0); Process process =new Process(account); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.start(); t2.start(); } } class Account{ private String name; private double yukuan; Account(String name,double yukuan){ this.name=name; this.yukuan=yukuan; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getYukuan() { return yukuan; } public void setYukuan(double yukuan) { this.yukuan = yukuan; } //对外提供取款操作 public void delete(double money) throws InterruptedException { //变为单线程 synchronized (this) { double after=this.yukuan-money; Thread.sleep(1000); this.yukuan=after; System.out.println("取款成功,剩余额为"+this.yukuan); } } } class Process implements Runnable{ Account account ; Process(Account account) { this.account=account; } public void run(){ try{account.delete(1000.0);} catch(InterruptedException e){ e.printStackTrace(); } } }发现代码的执行时间增长,代码的执行效率降低,但是数据的安全性得到了保证 原理: t1线程执行到同步语句块,遇到了synchronized关键字,就会去找synchronized(共享对象)内共享对象的对象锁,如果找到,则进入同步语句块执行程序,当同步语句块中的代码执行结束之后,t1线程归还共享对象的对象锁;在t1线程执行同步语句块的过程中,如果t2线程也过来执行同步语句块,就也要去找共享对象的对象锁,但是该对象锁被t1线程持有,所以t2线程只能等待t1线程执行完归还对象锁后才去执行同步语句块
在java中任何一个对象都有对象锁,即每一个对象都有0、1标志 第二种线程同步的方式
//演示使用线程同步机制的取款例子,多线程同时对同一个账户进行取款操作,使用线程同步机制保证数据安全 public class Test{ public static void main(String[] args) { Account account =new Account("Jack", 5000.0); Process process =new Process(account); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.start(); t2.start(); } } class Account{ private String name; private double yukuan; Account(String name,double yukuan){ this.name=name; this.yukuan=yukuan; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getYukuan() { return yukuan; } public void setYukuan(double yukuan) { this.yukuan = yukuan; } //对外提供取款操作 public synchronized void delete(double money) throws InterruptedException { double after=this.yukuan-money; Thread.sleep(1000); this.yukuan=after; System.out.println("取款成功,剩余额为"+this.yukuan); } } class Process implements Runnable{ Account account ; Process(Account account) { this.account=account; } public void run(){ try{account.delete(1000.0);} catch(InterruptedException e){ e.printStackTrace(); } } }synchronized关键字加到成员方法上 其实还是去找当前对象this的对象锁 一般采用第一种方式,第二种方式用于成员方法中所有的代码都需要同步的情况,此时程序的执行效率可能十分低下
StringBuffer、Vector、HashTabel类内含synchronized,因此它们都是线程安全的
遇synchronized就去找锁,找得到就去执行,找不到就等
//演示使用线程同步机制的取款例子,多线程同时对同一个账户进行取款操作,使用线程同步机制保证数据安全 public class Test{ public static void main(String[] args) throws InterruptedException{ Account account =new Account(); Process process =new Process(account); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.setName("t1"); t2.setName("t2"); t1.start(); //若想让m1方法先执行,可以添加延迟 Thread.sleep(1000); t2.start(); } } class Account{ public synchronized void m1() throws InterruptedException { Thread.sleep(2000); System.out.println("m1 is doing..."); } //m2没有synchronized,不会去找对象锁,不是线程同步,不会等m1 public void m2(){ System.out.println("m2 is doing..."); } } class Process implements Runnable{ Account account ; Process(Account account) { this.account=account; } public void run(){ if(Thread.currentThread().getName()=="t1") { try{ account.m1(); }catch(InterruptedException e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") account.m2(); } } //演示使用线程同步机制的取款例子,多线程同时对同一个账户进行取款操作,使用线程同步机制保证数据安全 public class Test{ public static void main(String[] args) throws InterruptedException{ Account account =new Account(); Process process =new Process(account); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.setName("t1"); t2.setName("t2"); t1.start(); //若想让m1方法先执行,可以添加延迟 Thread.sleep(1000); t2.start(); } } class Account{ public synchronized void m1() throws InterruptedException { Thread.sleep(2000); System.out.println("m1 is doing..."); } //m2有synchronized,就会去找对象锁,而对象又是共享的,是线程同步,m2会等m1 public synchronized void m2(){ System.out.println("m2 is doing..."); } } class Process implements Runnable{ Account account ; Process(Account account) { this.account=account; } public void run(){ if(Thread.currentThread().getName()=="t1") { try{ account.m1(); }catch(InterruptedException e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") account.m2(); } } //演示使用线程同步机制的取款例子,多线程同时对同一个账户进行取款操作,使用线程同步机制保证数据安全 public class Test{ public static void main(String[] args) throws InterruptedException{ Account account1 =new Account(); Account account2 =new Account(); Process process1 =new Process(account1); Process process2 =new Process(account2); Thread t1=new Thread(process1); Thread t2=new Thread(process2); //都没有共享对象,不是线程同步,m2不会等m1 t1.setName("t1"); t2.setName("t2"); t1.start(); //若想让m1方法先执行,可以添加延迟 Thread.sleep(1000); t2.start(); } } class Account{ public synchronized void m1() throws InterruptedException { Thread.sleep(2000); System.out.println("m1 is doing..."); } public synchronized void m2(){ System.out.println("m2 is doing..."); } } class Process implements Runnable{ Account account ; Process(Account account) { this.account=account; } public void run(){ if(Thread.currentThread().getName()=="t1") { try{ account.m1(); }catch(InterruptedException e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") account.m2(); } }在静态方法上添加synchronized关键字
public class Test{ public static void main(String[] args) throws InterruptedException{ Process process =new Process(); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); t2.start(); } } class Process implements Runnable{ public void run() { if(Thread.currentThread().getName()=="t1") { try{ Myclass.m1(); }catch(Exception e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") Myclass.m2(); } } class Myclass{ public synchronized static void m1() throws Exception { Thread.sleep(2000); System.out.println("m1 is doing..."); } public static void m2(){ System.out.println("m2 is doing..."); }//m2没有synchronized修饰,不会去找类锁,所以m2不会去等m1 } public class Test{ public static void main(String[] args) throws InterruptedException{ Process process =new Process(); Thread t1=new Thread(process); Thread t2=new Thread(process); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); t2.start(); } } class Process implements Runnable{ public void run() { if(Thread.currentThread().getName()=="t1") { try{ Myclass.m1(); }catch(Exception e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") Myclass.m2(); } } class Myclass{ public synchronized static void m1() throws Exception { Thread.sleep(2000); System.out.println("m1 is doing..."); } public synchronized static void m2(){ System.out.println("m2 is doing..."); }//m2有synchronized修饰,会去找类锁,所以m2会等m1 } public class Test{ public static void main(String[] args) throws InterruptedException{ //不同对象 Myclass myclass =new Myclass(); Myclass myclass2 =new Myclass(); Process process =new Process(myclass); Process process2 =new Process(myclass2); Thread t1=new Thread(process); Thread t2=new Thread(process2); //类锁,与对象无关,所以m2会去等m1 t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); t2.start(); } } class Process implements Runnable{ Myclass myclass; Process(Myclass myclass) { this.myclass=myclass; } public void run() { if(Thread.currentThread().getName()=="t1") { try{ Myclass.m1(); }catch(Exception e) { e.printStackTrace(); } } else if(Thread.currentThread().getName()=="t2") Myclass.m2(); } } class Myclass{ public synchronized static void m1() throws Exception { Thread.sleep(2000); System.out.println("m1 is doing..."); } public synchronized static void m2(){ System.out.println("m2 is doing..."); } }t1线程已经锁了o1,还要去锁o2;而t2线程已经锁了o2,还要去锁o1 t1、t2线程都不能执行完去释放各自拥有的锁,陷入僵持局面
public class Test{ public static void main(String[] args) throws InterruptedException{ Object o1=new Object(); Object o2=new Object(); //两个线程共享对象,如果都不是同一个对象的话怎么会造成死锁呢 Thread t1=new Thread(new Process(o1,o2)); Thread t2=new Thread(new Process2(o1,o2)); t1.start(); t2.start(); } } //两个线程所执行的run方法操作不同,所以可以写两个线程类 class Process implements Runnable{ Object o1; Object o2; Process(Object o1,Object o2) { this.o1=o1; this.o2=o2; } public void run() { synchronized(o1){ System.out.println("我已将o1上锁,我还想去锁o2"); try{ Thread.sleep(2000); }catch(InterruptedException e) { e.printStackTrace(); } synchronized(o2){ } } } } class Process2 implements Runnable{ Object o1; Object o2; Process2(Object o1,Object o2) { this.o1=o1; this.o2=o2; } public void run(){ synchronized(o2){ System.out.println("我已将o2上锁,我还想去锁o1"); try{ Thread.sleep(2000); }catch(InterruptedException e) { e.printStackTrace(); } synchronized(o1){ } } } }总结: 线程同步靠的就是锁,而线程同步的前提是 共享 类或对象,这点很重要
线程可分为用户线程和守护线程,守护线程在所有用户线程都结束后才能结束,如java的垃圾回收器就是一个守护线程,在应用程序的所有线程都结束后才能结束 JVM会自动启动一个主线程和垃圾回收器(守护线程)
守护线程一般都是无限执行的,在所有用户线程结束后自动结束
public class Test{ public static void main(String[] args) throws InterruptedException{ Thread t1=new Thread(new Process()); t1.setName("t1"); t1.start(); for(int i=0;i<10;i++) System.out.println(Thread.currentThread().getName()+"--->"+i); //此时t1为用户线程,会一直进行,主线程结束后t1也会继续执行 } } class Process implements Runnable{ public void run(){ int i=0; while(true) { System.out.println(Thread.currentThread().getName()+"--->"+i); i++; try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } public class Test{ public static void main(String[] args) throws InterruptedException{ Thread t1=new Thread(new Process()); t1.setName("t1"); t1.setDaemon(true);//设置为守护线程 t1.start(); for(int i=0;i<10;i++) System.out.println(Thread.currentThread().getName()+"--->"+i); //此时t1为守护线程,主线程结束后没有其他的用户线程了,t1会自动结束 } } class Process implements Runnable{ public void run(){ int i=0; while(true) { System.out.println(Thread.currentThread().getName()+"--->"+i); i++; try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } }