Java之多线程

本文详细介绍了Java中创建多线程的四种方式,包括继承Thread类、实现Runnable接口、实现Callable接口以及使用线程池。重点讨论了线程同步的方法,如同步代码块、同步方法和Lock锁,并通过售票示例解释了线程安全问题。此外,还涉及线程通信的wait、notify和notifyAll方法及其在生产者/消费者问题中的应用。
摘要由CSDN通过智能技术生成

一、多线程的创建

1、方式一:继承于Thread类

(1)创建一个继承于Thread类的子类
(2)重写Thread类的run() —> 将此线程执行的操作声明在run()中
(3)创建Thread类的子类的对象
(4)通过此对象调用start()

例子:遍历100以内的所有的偶数

//1.创建一个继承于Thread类的子类
class MyThread extends Thread{
   

    //2.重写Thread类的run()
    @Override
    public void run() {
   
        for (int i = 0; i < 100; i++) {
   
            if (i % 2 == 0) {
   
                System.out.println(Thread.currentThread().getName() + ":"
                        + i);
            }
        }
    }
}

public class ThreadTest {
   
    public static void main(String[] args) {
   
       //3.创建Thread类的子类的对象
        MyThread t1 = new MyThread();

        //4.通过此对象调用start()
        t1.start(); //(1)启动当前线程     (2)调用当前线程的run()
        /*
         * 问题一:我们不能通过直接调用run()的方式启动线程
           t1.run();

         * 问题二:再启动一个线程,遍历100以内的偶数。不可以让已经start()的线程
           去执行。会报IllegalThreadStateException异常
           t1.start();
         */
        //我们需要重新创建一个线程的对象
        MyThread t2 = new MyThread();
        t2.start();

        /*start函数之前的都是主线程做的事
        *  下面的打印操作和主线程调用的子线程是同时执行的,所以执行顺序没有谁先谁后
        *  执行结果和自己的CPU频率有关
        */

        //如下操作仍然是在main()线程中执行的。
        for (int i = 0; i < 100; i++) {
   
            System.out.println(Thread.currentThread().getName() + ":" +
                    i + "*****main()*******");
        }

    }

}

2、创建多线程的方式二:实现Runnable接口

(1)创建一个实现了Runnable接口的类
(2)创建类去实现Runnable中的抽象方法:run()
(3)创建实现类的对象
(4)将此对象作为参数传递到Thread()类的构造器中,创建Thread类的对象
(5)通过Thread类的对象调用start()

比较创建线程的两种方式:

  • 开发中:优先选择:实现Runnable接口的方式
  • 原因:
    1.实现的方式没有类的单继承性的缺陷型
    2.实现的方式更适合来处理多个线程有共享数据的情况。
  • 联系:public class Thread implements Runnable
  • 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
//1.创建一个实现了Runnable接口的类
class  MThread implements Runnable{
   

    //2.创建类去实现Runnable中的抽象方法:run()
    @Override
    public void run() {
   
        for(int i = 0; i < 100; i++){
   
            if(i % 2 == 0){
   
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadTest1 {
   
    public static void main(String[] args) {
   
        //3.创建实现类的对象
        MThread m = new MThread();

        //4.将此对象作为参数传递到Thread()类的构造器中,创建Thread类的对象
        Thread t1 = new Thread(m);

        //5.通过Thread类的对象调用start():
        //(1) 启动线程  (2)调用当前线程的run()---> 调用了Runnable类型的target的run()
        t1.setName("线程1");
        t1.start();

        //再启动一个线程,遍历100以内的偶数
        Thread t2 = new Thread(m);
        t2.setName("线程2");
        t2.start();

    }

}

二、Thread类中的常用方法

1、start():启动当前线程;调用当前线程的run()
2、run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3、currentThread():静态方法,返回执行当前代码的线程
4、gerName():获取当前线程的名字
5、setName():设置当前线程的名字
6、yield():释放当前CPU的执行权
7、join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
8、stop():已过时。当执行此方法时,强制结束当前线程。
9、sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内当前线程是阻塞状态
10、isAlive(): 判断当前线程是否存活
11、线程的优先级:
(1)MAX_PRIORITY: 10
(2) MIN _PRIORITY: 1
(3) NORM_PRIORITY: 5 —> 默认优先级

12、如何获取和设置线程的优先级:

  • getPriority(),获取线程的优先级
  • setPriority(),设置线程的优先级

说明:高优先级的线程要抢占低优先级cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

public class ThreadMethodTest {
   

    public static void main(String[] args) {
   
        HelloThread h1 = new HelloThread("Thread:1");

        //h1.setName("线程一");

        //设置分线程的优先级
        h1.setPriority(10);

        h1.start();

        //给当前主线程起名
        Thread.currentThread().setName("主线程");

        //设置主线程的优先级
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

        for(int i = 0; i < 100; i++){
   
            if(i % 2 == 0){
   
                System.out.println(Thread.currentThread().getName()
                        + ":" + Thread.currentThread().getPriority() + ":" + i);
            }

            if(i == 20){
   
                try {
   
                    h1.join();   //如果分线程没有被join,但其自身有睡眠阻塞的话,切换到主线程执行的频率大大加大
                                 //有join的话即使分线程有sleep,也是先执行完分线程再执行主线程
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
            }

            //System.out.println(h1.isAlive()); //false
        }

        System.out.println(h1.isAlive()); //false

    }
}

class HelloThread extends Thread{
   
    public HelloThread(String name){
   
        super(name);
    }
    @Override
    public void run() {
   
       for(int i = 0; i < 100; i++){
   
           if(i % 2 == 0){
   
               try {
      //不能用throws的方式,因为父类Thread中的run方没有throws异常
                   sleep(1);  //1000ms
               } catch (InterruptedException e) {
   
                   e.printStackTrace();
               }
           }
           if(i % 2 == 0){
   
               System.out.println(Thread.currentThread().getName()
                       + ":" + Thread.currentThread().getPriority() +  ":" + i);
               //这里可以省略Thread.currentThread()
           }

//           if(i % 20 == 0){
   
//               yield(); //与this.yield()和Thread.currentThread().yield()等价
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值