• 关于java多线程由浅到深的学习(一)


    最近正在使用java Thread,就重新学习了下Thread,写下博客用于对学习的梳理。

    1、Java线程的实现。

     第一种方式可以通过继承Thread。在Thread类中,有许多关于线程操作的方法,比如:sleep();activeCount();等

     继承Thread的代码:

    public class MyThread extends Thread{
        
        public static void main(String[] args) {
            MyThread myth = new MyThread();
         MyThread myth1 = new MyThread(); myth.start();//启动一个线程
         myth1.start(); } @Override
    public void run() { System.out.println(Thread.currentThread().getName());//得到当前线程名 } }

      第二种方式通过实现Runnable。通过重写run()方法,实现自己的业务逻辑。jvm会自动调用run()方法。

     实现Runnale的代码:

    public class RunThread implements Runnable {
    
            public void run() {
              System.out.print(Thread.currentThread().getName());
        }
            
            public static void main(String[] args){
            RunThread rtA = new RunThread();
            
            new Thread(rtA).start();
            new Thread(rtA).start();
            new Thread(rtA).start();
            System.out.println(Thread.activeCount());//当前活跃线程数
        }
    }

    二者的区别:

     我们可以从Thread源码得知,Thread实际上也是实现了Runnable接口。

      1、如果继承了Thread,那么就不能在去继承其他的类了,而实现Runnable接口就不会有这样的问题,提高类的可扩展性。

      2、从上面的代码看,第一种方式开启多个线程话,就必须创建多个对象;第二种方式开启多个线程,就可以只使用一个对象,这样就可以是实现资源的共享。

     以买票为列:

    package org.demo.dff;  
    class MyThread extends Thread{  
    private int ticket=10;  
    public void run(){  
    for(int i=0;i<20;i++){  
    if(this.ticket>0){  
    System.out.println("卖票:ticket"+this.ticket--);  
    }  
    }  
    }  
    };
    View Code

    下面通过三个线程对象,同时卖票:

    package org.demo.dff;  
    public class ThreadTicket {  
    public static void main(String[] args) {  
    MyThread mt1=new MyThread();  
    MyThread mt2=new MyThread();  
    MyThread mt3=new MyThread();  
    mt1.start();//每个线程都各卖了10张,共卖了30张票  
    mt2.start();//但实际只有10张票,每个线程都卖自己的票  
    mt3.start();//没有达到资源共享  
    }  
    } 

    如果用Runnable就可以实现资源共享,下面看例子:

    package org.demo.runnable;  
    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("卖票:ticket"+this.ticket--);  
    }  
    }  
    }  
    }  
    package org.demo.runnable;  
    public class RunnableTicket {  
    public static void main(String[] args) {  
    MyThread mt=new MyThread();  
    new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一  
    new Thread(mt).start();//个实例化对象mt,就会出现异常  
    new Thread(mt).start();  
    }  
    }; 

    2、线程的状态(state)

      新生状态(New):当一个线程的实例被创建时,即new的时候,此时线程处于一个新生状态,新生状态的线程有自己的内存空间,但是线程没有运行(调用start()运行),此时线程不是活的。(not alive)

      就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);

      运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);

      阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)

      死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thready已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)

    由于时间问题,有关synchronized和wait(),notify()将在下文中介绍。

  • 相关阅读:
    P1131 [ZJOI2007]时态同步(树形dp)
    P2831 愤怒的小鸟(状压dp)
    bzoj2456 / P2397 yyy loves Maths VI (mode)
    P1879 [USACO06NOV]玉米田Corn Fields(状压dp)
    P1026 统计单词个数
    P2679 子串
    数据库合并工具 esql
    在游戏中实现语音聊天和语音转化成文字
    在游戏中实现语音聊天和语音转化成文字
    类型强转的那些坑
  • 原文地址:https://www.cnblogs.com/duanzhiping/p/3583942.html
Copyright © 2020-2023  润新知