多线程一些基础实现
继承Thread类方式
1. 线程启动时:一定是调用Thread类的start()方法,因为通过源码解析发现,start()方法中,最后会调用以native关键字修饰的start0()方法,该方法会通过JVM实现不同操作系统不同实现的
资源调度分配;
2. Native关键字:调用本机的操作系统函数。
实现Runnable接口方式
1. 实现Runnable接口:由于继承Thread类会造成单继承的局限性,所以利用接口来实现;
2. Runnable接口:因为其是函数式接口,所以该接口中只有一个方法,可以使用Lamda表达式完成;
3. @FunctionalInterface:修饰的接口为函数式接口;
4. 由于启动发多线程只能通过start()方法,但Runnable方法中没有此方法,故实现该接口并启动一个线程,是通过Thread的构造函数发现:
public Thread(Runnable targer) ,所以可以通过此方式来启动一个多线程;
实例:Runnnable接口方式
public class Test11 { public static void main(String[] args) { Test11Demo t1 = new Test11Demo("线程1"); Test11Demo t2 = new Test11Demo("线程2"); Test11Demo t3 = new Test11Demo("线程3"); new Thread(t1).start(); new Thread(t2).start(); new Thread(t3).start(); }}class Test11Demo implements Runnable { private String name; Test11Demo(String name) { this.name = name; } @Override public void run() { for (int x = 0; x < 10; x++) { System.out.println(this.name + ",x=" + x); } } }
实例:Lamda方式,内部类方式
在原来代码基础上,添加测试代码
public static void main(String[] args) throws Exception { Test11Demo t1 = new Test11Demo("线程1"); Test11Demo t2 = new Test11Demo("线程2"); Test11Demo t3 = new Test11Demo("线程3"); new Thread(t1).start(); new Thread(t2).start(); new Thread(t3).start(); final String name1 = "Lamda测试"; new Thread( ()->{ for (int x = 0; x < 10; x++) { System.out.println(name1 + ",x=" + x); } }).start(); final String name = "内部类测试"; new Thread(new Runnable() { @Override public void run() { for (int x = 0; x < 10; x++) { System.out.println(name + ",x=" + x); } } }).start();}
两种方式,启动线程的异同
1. 查看源码可知,Thread类定义:
public classThread extends Object implements Runnable
2. 类关系图:
综上,可知,
多线程需要一个线程主类:可以继承Thread类,也可以实现Runnable接口;
使用Runnable接口,可以更好的实现数据共享的操作;并可以避免Thread类带来的单继承局限性;
线程的命名和取得
1. 线程的所有操作方法基本上都已经在Thread类中定义完整;
2. 如下方法,可提供线程名称操作:
① 构造方法:public Thread(Runnable target,String name)
② 设置名字:public final void setName(String name)
③ 获取名字:public final String getName()
④ 由于线程执行本身不确定状态,
提供方法:public static Thread currentThread()来取得当前线程
3. 如果在设置线程对象名称时,没有设置具体名字,则会采用默认名字进行定义;
4. 每一个JVM至少会启动两个线程:主线程,GC线程;
线程的休眠
休眠方法:sleep();线程的睡眠,是有先后顺序的
线程的优先级
1. 优先级操作方法:
设置优先级:public final void setPriority(int newPriority);
取得优先级:public final int getPriority();
2. 优先级相关常量:
最高优先级:public final static int MAX_PRIORITY = 10;
中等优先级:public final static int NORM_PRIORITY = 5;
最低优先级:public final static int MIN_PRIORITY = 1;
3. 理论上,会根据设置的优先级进行线程的启动运行;
主线程,属于一般优先级。
线程的同步与死锁
1. 同步问题的引出:多个线程需要访问统一资源;
2. 同步代码块执行效率要低于异步,同步代码块使用:synchronized关键字
3. 异步执行效率高,但数据不准确;同步代码执行效率慢,但会保证数据的有效性,同时线程安全。
4. 死锁:(了解) 如果程序中出现过多同步,将会产生死锁问题;
---下一篇,线程中的生产者与消费者理解--线程的应用场景之一