线程要依附进程存在
多线程的实现一定要有一个线程的主类,而主类往往需要操作一些资源,但对于多线程主类的实现有一定的要求:
1. 继承Thread父类;
2. 实现Runnable接口(Callable接口)
继承Thread类实现多线程:
在java.lang包有Thread类,子类继承Thread后要覆写Thread类中的run()方法,这个方法就属于线程的主方法。
定义:public void run();
范例:线程的主体类;
class MyThread extends Thread{ //表示实现多线程 private String name; public MyThread(String name) { //线程的名字 this.name = name; } @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 10; x++) { System.out.println(this.name + ", x = " + x); } } }
上面是将内容输出10次,所有的线程并发执行,即在一个时间段上会有多个线程交替执行,所以不能直接调用run方法,而应该调用Thread类中的start()方法启动多线程。
public void start()
范例:启动多线程
class MyThread extends Thread{ //表示实现多线程 private String name; public MyThread(String name) { //线程的名字 this.name = name; } @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 10; x++) { System.out.println(this.name + ", x = " + x); } } } public class Hello{ public static void main(String[] args) { MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); MyThread mt3 = new MyThread("线程C"); mt1.start(); mt2.start(); mt3.start(); } }
结果混乱,是因为交替执行,没有固定的执行顺序。若不调用start而调用run,就是顺序执行
实现Runnable接口
继承Thread会有单继承的局限,所以最好的做法是利用接口来解决,于是使用Runnable接口。
public interface Runnable { public void run(); }
按照正常思路实现Runnable多线程:
class MyThread implements Runnable{ //表示实现多线程 private String name; public MyThread(String name) { //线程的名字 this.name = name; } @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 10; x++) { System.out.println(this.name + ", x = " + x); } } }
此时如果想开始多线程,由于现在实现的是Runnable接口,所以无法用Thread类中的start方法了,现在使用匿名内部类来使用start方法
class MyThread implements Runnable{ //表示实现多线程 private String name; public MyThread(String name) { //线程的名字 this.name = name; } @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 10; x++) { System.out.println(this.name + ", x = " + x); } } } public class Hello{ public static void main(String[] args) { MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); MyThread mt3 = new MyThread("线程C"); new Thread(mt1).start(); //匿名 new Thread(mt2).start(); new Thread(mt3).start(); } }
面试题
继承Thread类和Runnable接口两种实现方式的区别:
多线程一定需要一个线程的主类,要么继承Thread类,要么实现Runnable接口
使用Runnable接口可以比Thread更好实现数据共享操作,利用Runnable接口可以避免单继承局限问题
Thread类实现了Runnable接口。
Runnable接口实现的多线程要比Thread类实现的多线程更方便的表现出数据共享的概念
范例:希望有三个线程进行买票 - Thread实现会发现三个线程各自卖各自的票,票没有了其他线程也不知道
class MyThread extends Thread{ //表示实现多线程 private int ticket = 5; @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 50; x++) { if(this.ticket>0) { System.out.println("卖票,ticket = " + this.ticket --); } } } } public class Hello{ public static void main(String[] args) { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); mt1.start(); mt2.start(); mt3.start(); } }
使用Runnable接口实现:
class MyThread implements Runnable{ //表示实现多线程 private int ticket = 5; @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 50; x++) { if(this.ticket>0) { System.out.println("卖票,ticket = " + this.ticket --); } } } } public class Hello{ public static void main(String[] args) { MyThread mt = new MyThread(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); } }
Callable接口:
比Runnable的好处是可以返回值
class MyThread implements Callable<String>{ //表示实现多线程 private int ticket = 5; @Override public String call() { //覆写run()方法,线程的主方法 for(int x = 0; x < 50; x++) { if(this.ticket>0) { System.out.println("卖票,ticket = " + this.ticket --); } } return "票卖完了"; } } public class Hello{ public static void main(String[] args) throws InterruptedException, ExecutionException { Callable<String> cal = new MyThread(); FutureTask<String> task = new FutureTask<>(cal); Thread thread = new Thread(task); thread.start(); System.out.println(task.get()); //取得线程主方法的返回值 } }
线程休眠
可以让某些线程延缓执行
休眠方法:public static void sleep (long millis) throws InterruptedException;
如果休眠时间没到就停止休眠了,那么就会产生中断异常。
Thread.sleep(1000); 加上这一句,延迟一秒,会有报错,点报错纠错就对了
class MyThread implements Runnable{ //表示实现多线程 @Override public void run() { //覆写run()方法,线程的主方法 for(int x = 0; x < 100; x++) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //休眠一秒 System.out.println(Thread.currentThread().getName() + ", x = " + x); } } } public class Hello{ public static void main(String[] args) throws InterruptedException, ExecutionException { MyThread mt = new MyThread(); new Thread(mt, "线程A").start(); new Thread(mt, "线程B").start(); new Thread(mt, "线程C").start(); } }
线程的优先级
优先级越高的线程越有可能先执行,而在Thread类定义一下优先级方法
设置优先级:public final void setPriority(int newPriority);
取得优先级:public final int getPriority();
优先级定义有三种:
最高优先级:public static final int MAX_PRIORITY,10;
中等优先级:public static final int NORM_PRIORITY,5;
最低优先级:public static final int MIN_PRIORITY,1;
class MyThread implements Runnable{ @Override public void run() { for(int x = 0; x < 100; x++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ", x = " + x); } } } public class Hello{ public static void main(String[] args) throws InterruptedException, ExecutionException { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "线程A"); Thread t2 = new Thread(mt, "线程B"); Thread t3 = new Thread(mt, "线程C"); t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY); t3.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); t3.start(); } }
设置优先级只是理论上的,不一定真的就是优先
范例:主线程的优先级是什么
public class Hello{ public static void main(String[] args) throws InterruptedException, ExecutionException { System.out.println(Thread.currentThread().getPriority()); } }
结果是5,主线程属于中等优先级
总结:
线程要有名字,Thread.currentThread取得当前线程;
线程的休眠有先后顺序
优先级越高理论上越有可能先执行
线程同步,多线程需要访问同一资源
同步代码块:使用synchronized关键字定义的代码块就是同步代码块,但同步的时候需要设置一个同步对象,往往使用this同步当前对象。
范例:买票,买票最后票的数量不能出现负数
class MyThread implements Runnable{ private int ticket = 50; @Override public void run() { for(int x = 0; x < 100; x ++) { synchronized (this) { //同步代码块 if(this.ticket > 0) { try { Thread.sleep(100); //延迟一秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ", ticket = " + this.ticket --); } } } } } public class Hello{ public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); Thread t1 = new Thread(mt,"票贩子A"); Thread t2 = new Thread(mt,"票贩子B"); Thread t3 = new Thread(mt,"票贩子C"); t1.start(); t2.start(); t3.start(); } }
另一种实现方式,synchronized方法
class MyThread implements Runnable{ private int ticket = 5; @Override public void run() { for(int x = 0; x < 10; x ++) { this.sale(); } } public synchronized void sale() { //卖票 if(this.ticket > 0) { try { Thread.sleep(100); //延迟一秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ", ticket = " + this.ticket --); } } } public class Hello{ public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); Thread t1 = new Thread(mt,"票贩子A"); Thread t2 = new Thread(mt,"票贩子B"); Thread t3 = new Thread(mt,"票贩子C"); t1.start(); t2.start(); t3.start(); } }