- 多线程并发与单线程,效率多线程并不比单线程更快,只是我们感官上感觉多线程并发更快
- 创建线程的两种方式:
- 继承Thread类,重写run();方法,启动线程调用start();方法
- 实现Runnable接口
- 继承Thread类:
/**
* 多线程:
* 线程:一个顺序的单一的程序执行流程就是一个线程。代码一句一句的有先后顺序的执行。
* 多线程:多个单一顺序执行的流程并发运行。造成“感官上同时运行的效果”
*
* 多个线程实际运行是走走停停的,线程调度程序会将CPU运行时间发分为若干个 时间片段 并尽可能
* 均匀的分配给每个线程,拿到时间片的线程被CPU执行这段时间。
* 当超时后线程调度程序会再次分配一个时间片段给一个线程使得CPU执行它。
* 如此反复。由于CPU执行时间在纳秒级别,我们感觉不到切换线程运行的过程。
* 所以微观上走走停停,宏观上感觉一起运行的线程称为并发运行!
*
*
* 第一种创建线程的方式:
* 定义一个类继承Thread,并重写run方法。在run方法中定义要与其线程并发运行的任务
* 启动线程时要使用start方法!
*
* 继承:有一个问题,就是线程定义好了,就定义了并发干的事,
* 线程和线程的任务绑定死了,局限
*/
public class ThreadDemo1 extends Thread {
public static void main(String[] args) {
Thread demo2 = new ThreadDemo2();
Thread demo34 = new ThreadDemo34();
//run()方法是干的活,是任务
//启动线程用start()方法,调用线程,就不考虑先后调用的问题了
demo2.start();
demo34.start();
}
}
/**
* 第一种创建线程的方式优点在于结构简单,便于匿名内部类形式创建
* 缺点:
* 1、直接继承线程,会导致不能再继承其他类去复用方法,这在实际开发中非常不便
* 2、定义线程的同时重写了run方法,会导致线程与线程任务绑定在了一起,不利于线程的重用
*
*/
class ThreadDemo2 extends Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println("你是谁");
}
}
}
class ThreadDemo34 extends Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println("查水表的");
}
}
}
- 实现Runnable接口:
/**
* 第二种创建线程的方式
* 实现Runnable 接口单独定义线程任务
*
* 单独去定义线程任务,不再是绑定线程任务了
* 线程的重用,有线程任务后,只需要new
*/
public class ThreadDomo2 {
public static void main(String[] args) {
/**
* 将线程任务,和创建线程分开了
*/
//实例化线程任务
Runnable run1 = new MyRunnable1();
Runnable run2 = new MyRunnable2();
//创建两个线程
Thread thread1 = new Thread(run1);
Thread thread2 = new Thread(run2);
//启动线程
thread1.start();
thread2.start();
}
}
class MyRunnable1 implements Runnable{
public void run(){
for(int i=0;i<100;i++){
System.out.println("你是谁");
}
}
}
class MyRunnable2 implements Runnable{
public void run(){
for(int i=0;i<100;i++){
System.out.println("is m");
}
}
}
- 两种方式的匿名内部类创建线程
/**
* 以匿名内部类的形式完成线程的两种创建方式
*/
public class ThreadDemo3 {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for(int i=0;i<50;i++){
System.out.println("你是谁");
}
}
}.start();
new Thread(new Runnable(){
public void run(){
for(int i=0;i<50;i++){
System.out.println("急啊急啊");
}
}
}).start();
Runnable run = ()-> System.out.println("123");
}
}
- main方法是主线程,可以获取线程的名字
/**
* java中所有的代码都是靠线程运行的,main方法也不例外
* java程序开始运行时,JVM会创建一条线程来执行main方法。这条运行main方法的线程的名字
* 叫做main,也称他为主线程
*
* 线程提供了一个静态方法,可以获取到运行该方法的线程
* static Thread currentThread()
*
* 调用start方法CPU才会分配时间片
*/
public class ThreadDemo4 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println("main线程是:"+thread);//main线程是:Thread[main,5,main]
dosome();//dosome方法线程是:Thread[main,5,main]
System.out.println("main方法执行完毕");
Thread thread1 = new Thread(){
public void run(){
Thread p = Thread.currentThread();
System.out.println("自定义线程"+p+"开始执行");//自定义线程Thread[Thread-0,5,main]开始执行
dosome();//dosome方法线程是:Thread[Thread-0,5,main]
System.out.println("自定义线程"+p+"执行结束");//自定义线程Thread[Thread-0,5,main]执行结束
}
};
thread1.start();
}
public static void dosome(){
Thread thread = Thread.currentThread();
System.out.println("dosome方法线程是:"+thread);
}
}
- 获取线程相关信息的一组方法:
public class ThreadDemo5 {
public static void main(String[] args) {
Thread t1 = Thread.currentThread();
//获取线程的名字
String name = t1.getName();
System.out.println(name);
long id = t1.getId();//获取线程的唯一id
System.out.println(id);
int poi = t1.getPriority();//获取该线程的优先级
System.out.println(poi);//默认是5
//判断线程是否活着
boolean a = t1.isAlive();
//判断是否是守护线程
t1.isDaemon();
//判断线程是否被中断了
t1.isInterrupted();
}
}
- void setPriority(int i);线程的优先级(不一定,只是最大程度上分配时间片):
/**
* 线程的优先级
* 线程有10个优先级,使用整数1-10来表示
* 1为最小优先级
* 10为最高优先级
* 5为默认值
* 线程start后会纳入到线程调度器中统一管理
* 线程只能被动的被分配时间片并发运行,而无法
* 主动索取时间片,线程调度器尽可能均匀的将时间片分配给每个线程
* 调整线程的优先级可以最大程度的干涉获取时间片的几率,优先级越高的线程获取时间片的次数
* 越多,反之则越少
*
*/
public class ThreadDemo6 {
public static void main(String[] args) {
Thread max = new Thread(){
public void run(){
for(int i=0;i<50;i++){
System.out.println("max");
}
}
};
Thread min = new Thread(){
public void run(){
for(int i=0;i<50;i++){
System.out.println("min");
}
}
};
Thread norm = new Thread(){
public void run(){
for(int i=0;i<50;i++){
System.out.println("norm");
}
}
};
//设置优先级,有几率,但不准 最大程度的干涉获取时间片的几率
norm.setPriority(Thread.MIN_PRIORITY);
min.setPriority(Thread.NORM_PRIORITY);
max.setPriority(Thread.MAX_PRIORITY);
norm.start();
min.start();
max.start();
}
}
- sleep方法,睡眠
/**
* 线程提供了一个静态方法
* static void sleep(ling ms)
* 使运行该方法的线程进入阻塞状态指定的毫秒,超时后线程会自动回到Runnalbe状态等待再次获取
* 时间片并发运行
*/
public class ThreadDemo7 {
public static void main(String[] args) {
/**
* 要求用户输入一个数字,然后从该数字开始每秒递减,到0时输出时间到,程序结束
*/
while (true){
System.out.println("请输入一个数字...");
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
String regex = "[0-9]+";
if(str.matches(regex)){
int num = Integer.valueOf(str);
for(int i=num;i>=0;i--){
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("计时结束...");
break;
}else{
System.out.println("格式不符,请重新输入...");
}
}
}
}