Java多线程实现与应用

什么是多线程?

多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”(源自:百度百科)

多线程的创建!

方式一

继承于Thread类方式
步骤:

  • 创建一个继承与Thread类的子类
  • 重写Thread类的run()方法
  • 创建子类的对象
  • 调用start()方法
    • start方法作用:
      • 启动当前线程
      • 调用当前线程的run方法
      • 一个对象只能调用一次,调用两次相当于创建了两个一样的线程,会出异常
package Thread;

class mythread extends Thread{//创建一个继承与Thread类的子类
    @Override
    public void run() {//重写Thread类的run()方法
        for (int i = 0; i <100 ; i++) {
            if(i%2==0){
                System.out.println(i);//输出100以内的偶数
            }
        }
    }
}
public class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();//创建子类的对象
        thread1.start();//调用start()方法
    }
}

可能觉得和普通的方法没啥区别,那看下面的代码:(我在main方法里面也添加了一个循环,输出加了一些文字,为了和次线程区分,数字也改变了,因为太小可能看不出来 )

package Thread;

class mythread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <10000 ; i++) {
            if(i%2==0){
                System.out.println(i);
            }
        }
    }
}
public class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();
        thread1.start();
        for (int i = 0; i <10000 ; i++) {
            if(i%2==0){
                System.out.println(i+"主线程");
            }
        }
    }
}

输出如下:
在这里插入图片描述
这里就显现出这是创建了一个主线程之外的线程,两者并行运行,输出结果无法预料。如果没有创建线程,则应该会先输出run方法里面的偶数,再输出下面添加了文字的偶数。注意:你也可以不用start()方法来直接调用run()方法,但这就和普通的方法没有区别,并不会独立于主线程之外
如果你想要看下数字少的是否有区别,这就要调用一个方法,看下面代码:

package Thread;

class mythread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//这个方法是得到该线程的名称
            }
        }
    }
}
public class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();
        thread1.start();
        for (int i = 0; i <10 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}

输出如下:
在这里插入图片描述
由此可见他们的区别,一个是我们创建的线程输出的,一个是main,也就是主线程输出的。名字为Thread-0是因为并没有给线程赋予名字。也可以用这个来区分调用start和run的区别

package Thread;

class mythread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
        }
    }
}
public class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();
//        thread1.start();
        thread1.run();
        for (int i = 0; i <10 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
        }
    }
}

输出如下:
在这里插入图片描述
结果表明这和普通的方法并没有区别,失去了创建多线程的意义,而且无论数字多大,都是先输出run方法里面的,因为代码是顺序执行的。

线程的常用方法

start():启动当前线程,并且调用当前线程的run()方法
run():一般需要重写,将创建的线程要执行的操作声明在此类中
currentThread():静态方法,返回执行当前代码的线程
getName():获得当前线程的名字
setName():设置当前线程的名字 设置名字要在线程开始之前,也就是在调用start()方法之前
yield():释放当前cpu的执行权(释放了,但是之后的分配是预测不到的,也有可能再次分配到当前线程)
join:在线程a中调用线程b的join方法,此时a就进入阻塞状态,直至线程b执行完之后,线程a才解除阻塞状态。
sleep(long millitime):让当前线程睡眠指定的millitime毫秒
isAlive():判断当前线程是否存活

class mythread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
            try {
                sleep(100);//睡眠100毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i%10==0){
                yield();//释放CPU的执行权
            }
        }
    }
}
public class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();
        thread1.setName("线程一");
        Thread.currentThread().setName("主线程");
        thread1.start();
        for (int i = 0; i <100 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
            if (i==50){
                try {
                    thread1.join();//当i=50的时候,执行thread1线程,把主线程阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(thread1.isAlive());//判断线程是否存活
    }
}

线程的优先级

线程的优先级:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
setPriority():设置线程的优先级
getPriority:获取线程的优先级
注意: 并不是设置了优先级就一定会先执行,只是执行的优先级高了,主要还是要看CPU的分配,也不是没有用,会提升调用执行的概率。

class mythread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
            //这里注释sleep方法是为了更好的体现优先级的影响,如果设置了,就算优先级高,但是要睡眠一定时间,就会让优先级低的执行
//            try {
//                sleep(100);//睡眠100毫秒
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            if (i%10==0){
                yield();//释放CPU的执行权
            }
        }
    }
}
class thread {
    public static void main(String[] args) {
        mythread thread1 = new mythread();

        thread1.setName("线程一");
        thread1.setPriority(Thread.MAX_PRIORITY);

        Thread.currentThread().setName("主线程");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

        thread1.start();

        for (int i = 0; i <100 ; i++) {
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);//输出100以内的偶数
            }
            //这里注释是为了更好的体现优先级的影响,因为join方法的功能会阻碍优先级的影响
//            if (i==50){
//                try {
//                    thread1.join();//当i=50的时候,执行thread1线程,把主线程阻塞
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }
        System.out.println(thread1.isAlive());//判断线程是否存活
    }
}

方式二

实现Runnable接口
步骤如下:

  • 创建一个类实现Runnable接口的类
  • 实现类去实现Runnable中的抽象方法:run()
  • 创建实现类的对象
  • 将此对象作为参数Thread类的构造器中,创建Thread类对象
  • 通过Thread类对象调用start()方法
public class thread2 {
    public static void main(String[] args) {
    
        myThread threadOne=new myThread();//创建实现接口的对象
        
        Thread t1=new Thread(threadOne);//创建Thread类对象
        
        t1.setName("线程ONE");
        t1.start();
    }

}
class myThread implements Runnable{//创建一个类实现Runnable接口的类

    @Override
    public void run() {//重写run()方法
        for (int i = 0; i <100 ; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);//输出100以内的偶数
            }
        }
    }
}

这里的调用run()方法有点不同之处,这里调用了Runnable里的target的run()方法,而target就是输入到Thread类里面的参数,在Thread类里面,他的形参就叫target,简而言之,就是target=threadOne

可以用的方法与方式一相同

方式的比较

区别:
1.首先方式二比较好一点,也就是实现Runna接口,因为Java里面不能多继承,可以多接口,因为到后面,去做一些大型的项目时候,有的类已经继承自其他的类,这时候想要实现多线程,只能采用实现Runnable接口,也就是方式二适用范围较广。==实现的方式没有类单继承性的局限性。这也是接口和继承的不同
2. 实现Runna接口的方法可以直接实现数据共享,而不需要像继承的那样设置为静态变量才可以进行数据共享,实现方式更适合处理多个线程有共享数据的情况。

联系:

  • Thread也实现了Runnable接口

相同:

  • 都需要重写run()方法,将线程要执行的行为声明在run()中
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值