zoukankan      html  css  js  c++  java
  • Java多线程基础(一)

    一、基本概念

    线程状态图包括五种状态

    1、新建状态(New):线程对象被创建后,就进入新建状态。例如,Thread thread=new Thread();

    2、就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其他线程调用了该对象的start()方法,从而来启动该线程。例如thread.start();处于就绪状态的线程,随时可能被CPU调度执行。

    3、运行状态(Running):线程获取CPU权限进行执行。注意,线程只能从就绪状态进入到运行状态。

    4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分为三种:

      (1)、等待阻塞:通过调用线程的wait()方法,让线程等待某个工作的完成。

      (2)、同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程所占用),它会进入同步阻塞状态。

      (3)、其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    5、死亡状态(Dead):线程执行完了,或者因异常退出了run()方法,该线程结束生命周期。

     二、实现多线程常用的两种方式:Thread和Runnable;【线程池(在java.util.concurrent包中)也可以实现多线程,后面讲解】

    1、Thread和Runnable异同

      (1)相同点:都是“多线程的实现方式”。

      (2)不同点:Runnable是接口只包含一个Run()方法;实现方式可以定义一个类A实现该接口,通过new Thread(new A())等方式新建线程。Runnable接口代码如下:        

    public interface Runnable {
        public abstract void run();
    }

         Thread是实现了Runnable接口的一个类。如:public class Thread implements Runnable {}

         我们知道“一个类只能有一个父类,但却能实现多个接口”,因此Runnable具有更好的可扩展性。此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某

       一个Runnable对象建立的,它们会共享Runnable对象上建立的资源。通常建议通过Runnable实现多线程

    2、Thread多线程示例

    示例代码如下:

    import java.util.ArrayList;
    
    public class MyThread extends Thread {
        private int ticket = 10;
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                if (this.ticket>0){
                    System.out.println(this.getName()+"卖票:ticket"+this.ticket--);
                }
            }
        }
    }
    
    import org.junit.Test;
    
    public class ThreadTest {
        @Test
        public void demo1() {
            //启动三个线程,t1,t2,t3;每个线程各卖十张票
            MyThread t1 = new MyThread();
            MyThread t2 = new MyThread();
            MyThread t3 = new MyThread();
            t1.start();
            t2.start();
            t3.start();
    //        t1.run();
    //        t2.run();
    //        t3.run();
        }
    }
    Thread示例代码
    Thread-1卖票:ticket10
    Thread-2卖票:ticket10
    Thread-1卖票:ticket9
    Thread-0卖票:ticket10
    Thread-1卖票:ticket8
    Thread-2卖票:ticket9
    Thread-1卖票:ticket7
    Thread-0卖票:ticket9
    Thread-1卖票:ticket6
    Thread-2卖票:ticket8
    Thread-1卖票:ticket5
    Thread-1卖票:ticket4
    Thread-0卖票:ticket8
    Thread-1卖票:ticket3
    Thread-2卖票:ticket7
    Thread-1卖票:ticket2
    Thread-1卖票:ticket1
    Thread-0卖票:ticket7
    Thread-0卖票:ticket6
    Thread-0卖票:ticket5
    ThThread-0卖票:ticket4
    运行结果

    测试方法属于一个主线程,在里面创建了三个子线程,根据线程内安全,每个线程都会卖出10张票。

    3、Runnable多线程示例

    示例代码如下:

    package RunnableDemo;
    
    public class MyThread implements Runnable {
        private int ticket = 10;
    
        public void run() {
            for (int i = 0; i < 20; i++) {
                if (this.ticket > 0) {
                    System.out.println(Thread.currentThread().getName()+ "卖票:ticket" + this.ticket--);
                }
            }
        }
    }
    
    
    package RunnableDemo;
    
    import ThreadDemo.ThreadTest;
    import org.junit.Test;
    
    public class RunnableTest {
        @Test
        public void demo1() {
            MyThread myThread = new MyThread();
            //启动三个线程t1,t2,t3(共用一个Runnable对象),这三个线程一共卖10张票
            Thread t1 = new Thread(myThread);
            Thread t2 = new Thread(myThread);
            Thread t3 = new Thread(myThread);
            t1.start();
            t2.start();
            t3.start();
        }
    }
    Runnable示例代码
    Thread-1卖票:ticket10
    Thread-0卖票:ticket9
    Thread-1卖票:ticket8
    Thread-2卖票:ticket6
    Thread-0卖票:ticket7
    Thread-2卖票:ticket4
    Thread-1卖票:ticket5
    Thread-2卖票:ticket2
    Thread-0卖票:ticket3
    Thread-1卖票:ticket1
    运行结果

    主线程创建并启动了三个子线程,而且这三个子线程都是基于“myThread这个Runnable对象”而创建的。运行结果显示这三个线程共同卖出10张票,说明它们共享了Runnable接口。

    4、Thread中start()和run()方法区别
    (1)、run()方法属于主线程方法,可以当做普通方法使用,在主线程中按照顺序执行,不新开线程,当上一个run()方法体执行完后,下一个run()方法才可以继续,没有达到多线程的目的;

    (2)、start()方法来启动线程,真正实现了多线程运行。start()方法启动线程后,线程处于就绪状态,并未运行。然后通过Thread类调用实现Thread类的run()方法,run()方法运行结束标志线程终止。在run()方法执行过程中,其他子线程无需等待某子线程run()方法执行完成,而是由CPU调度执行哪个子线程。start()方法不能被重复调用,否则会抛IllegalThreadStateException异常

    也可以通过运行代码,查看当前运行线程名字来判断

    package StartVSRun;
    
    public class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+" is running");
        }
    }
    
    
    package StartVSRun;
    
    import ThreadDemo.ThreadTest;
    import org.junit.Test;
    
    public class SVSR {
        @Test
        public void demo1() {
            Thread myThread = new MyThread("myThread");
            System.out.println(Thread.currentThread().getName() + " call myThread.run()");
            myThread.run();
            System.out.println(Thread.currentThread().getName() + " call myThread.start()");
            myThread.start();
        }
    }
    测试代码
    main call myThread.run()
    main is running
    main call myThread.start()
    myThread is running
    运行结果
  • 相关阅读:
    NOI2021 题解
    CF605E Intergalaxy Trips
    P4762 [CERC2014]Virus synthesis
    特征向量与特征值
    uoj
    NOI 2021
    [NOI2011] NOI 嘉年华 【DP】
    CF1264D(组合数)
    绝对不咕
    题解 SP11985 【GOT
  • 原文地址:https://www.cnblogs.com/hujiapeng/p/4814280.html
Copyright © 2011-2022 走看看