zoukankan      html  css  js  c++  java
  • 【Java】多线程相关复习—— 线程的创建、名字、运行情况以及顺序控制(join方法) 【一】

    一、创建线程的三种方式

    · 继承Thread类

    · 实现Runnable接口

    · 实现Callable接口

    二、 线程状态

    · 线程名字 getName()

    · 线程活动情况 isAlive()

    · 控制线程运行次序 join()

    一、 创建线程的三种方式

    ① 继承Thread类

    /**
     * 步骤:
     * 继承Thread重写run方法,创建该线程实例,调用start()方法启动线程
     * @author ChristineBassoon
     *
     */
    public class test {
    	public static void main(String[] args) {
    		MyThread t = new MyThread();
    		t.start();
    	}
    	
    }
    
    class MyThread extends Thread{
    
    	@Override
    	public void run() {
    		for(int i=0;i<50;i++) {
    			System.out.println(i+"["+this.getName()+"]");
    		}
    	}
    }

     同种方法以匿名内部类形式

    new Thread(){
      @Override
      public void run() {
        for(int i=0;i<50;i++) {
          System.out.println(i+"["+Thread.currentThread().getName()+"]");
        }
      }
    }.start();
    

    ② 实现Runnable接口

    /**
     * 步骤:
     * 实现Runnable接口,重写run方法,以此Runnable实例作为Thread的target创建Thread对象
     * 调用start方法启动线程
     * @author ChristineBassoon
     *
     */
    public class test {
    	public static void main(String[] args) {
    		Thread t = new Thread(new MyRunnable());
    		t.start();
    	}	
    }
    
    class MyRunnable implements Runnable{
    
    	@Override
    	public void run() {
    		for(int i=0;i<50;i++) {
    			System.out.println(i+"["+Thread.currentThread().getName()+"]");
    		}
    	}
    }
    
    //匿名内部类形式
    new Thread(new Runnable(){
        @Override
        public void run() {
          for(int i=0;i<50;i++) {
            System.out.println(i+"["+Thread.currentThread().getName()+"]");
          }
        }
      }).start();
    }
    

    ③ Callable方式

    /**
     * 步骤:
     * 1. 实现Callable接口,使用FutureTask类来包装Callable对象
     * 2. FutureTaskd对象作为Thread对象的target创建并启动线程
     * (FutureTask同时实现了Runnable和Callable接口,所以能作为Thread对象的的target)
     * 3. FutureTask的get()方法在子线程结束后可获得返回值(以此判断线程能否正常运行)
     */
    public class test {
    	public static void main(String[] args) {
    		
    		CallableThread ct = new CallableThread();  
            FutureTask ft = new FutureTask<>(ct);
            new Thread(ft).start();
            try {
    			System.out.println("子线程返回值为:"+ft.get());
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		} catch (ExecutionException e) {
    			e.printStackTrace();
    		}
    	}
    	
    }
    
    class CallableThread implements Callable {
    
    	@Override
    	public Integer call() throws Exception {
    		for(int i=0;i<50;i++) {
    			System.out.println(i+"["+Thread.currentThread().getName()+"]");
    		}
    		return 1;
    	}
    }
    

    二、线程状态

    线程的几个状态可用图概括 (图源自google image),解释得非常清楚

    //获取当前线程的名字
    Thread.currentThread().getName();
    //判断当前线程运行情况
    Thread.currentThread().isAlive();
    //设定线程的名字
    Thread.currentThread().setName("");
    //只有该线程结束后,程序才会向下进行
    [new Thread()].join();//[]表示某线程
    
    

    ① 获取当前线程名字 —— getName()

    情况1,获取主线程名字

    public class ThreadTest {
    	public static void main(String[] args) {
            System.out.println(Thread.currentThread().getName());
    
    	}
    }
    

     结果为

    main
    View Code

    情况2:获取子线程名字

    new Thread() {
        @Override
        public void run(){
            for(int i=0;i<5;i++) {
            System.out.println(i+"["+Thread.currentThread().getName()+"]");
            System.out.println(i+"["+this.getName()+"]");
            }
        }
    }.start();
    

     结果为

    0[Thread-0]
    0[Thread-0]
    1[Thread-0]
    1[Thread-0]
    2[Thread-0]
    2[Thread-0]
    3[Thread-0]
    3[Thread-0]
    4[Thread-0]
    4[Thread-0]
    View Code

    可看出,子程序运行期间,当前的线程( Thread.currentThread() )名字就是子程序的线程名。

    ②线程运行情况,判断线程是否在运行当中—— isAlive()

    public class ThreadTest {
    	public static void main(String[] args) {
    		MyThread myThread = new MyThread();
    		myThread.start();
    		System.out.println("");
    		try {
    			myThread.join();//确保子线程结束后才执行下方语句
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("");
    		System.out.println("myThread线程运行情况:"+myThread.isAlive());
    	}
    }
    
    class MyThread extends Thread {
    	
    	public MyThread(){
    		System.out.println("====构造函数开始====");
    		System.out.println(this.isAlive());
    		System.out.println("====构造函数结束====");
    	}
    	
    	@Override
    	public void run(){
    		System.out.println("=====run开始======");
    		System.out.println(this.isAlive());
    		System.out.println("=====run结束======");
    	}
    }
    
    

     结果为:

    ====构造函数开始====
    false
    ====构造函数结束====
    
    =====run开始======
    true
    =====run结束======
    
    myThread线程运行情况:false
    View Code

     总结:子线程只有调用start()方法后才会运行。

    ③ 线程之间的运行顺序 —— join() 方法的调控

     接下来我们实验一下:

    public class condition {
    	public static void main(String[] args) {
    		
    		MyThread myThread = new MyThread();
    		myThread.setName("子线程");//设定子线程名字
    		myThread.start();
    		System.out.println();
    		System.out.println("主线程运行完毕");
    	}
    }
    
    
    class MyThread extends Thread {
    	
    	@Override
    	public void run(){
    		for(int i=0;i<20;i++) {
    			System.out.println(i+"["+this.getName()+"]");
    		}
    	}
    }
    

    结果:

    主线程运行完毕
    0[子线程]
    1[子线程]
    2[子线程]
    3[子线程]
    4[子线程]
    5[子线程]
    6[子线程]
    7[子线程]
    8[子线程]
    9[子线程]
    10[子线程]
    11[子线程]
    12[子线程]
    13[子线程]
    14[子线程]
    15[子线程]
    16[子线程]
    17[子线程]
    18[子线程]
    19[子线程]
    View Code

    如果按照执行次序,本来应该最后打印的内容应该最后显示的,现在却放在最前头了。事实上,线程之间会互相争夺cpu资源,谁先抢到谁执行,像上述这种情况,则是主线程先抢到了cpu资源。如果必须保证先执行子线程,最后再执行主线程的打印动作的话,可以使用 join() 方法控制线程之间的执行次序。

    我们再来实验一下主线程和单个子线程

    public class condition {
    	public static void main(String[] args) {
    		
    		MyThread myThread = new MyThread();
    		myThread.setName("子线程");//设定子线程名字
    		myThread.start();
    		try {
    			myThread.join(); 
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		} 
    		
    		System.out.println("主线程运行完毕");
    	}
    }
    
    class MyThread extends Thread {
    	
    	@Override
    	public void run(){
    		for(int i=0;i<5;i++) {
    			System.out.println(i+"["+this.getName()+"]");
    		}
    	}
    }
    

     结果为

    0[子线程]
    1[子线程]
    2[子线程]
    3[子线程]
    4[子线程]
    主线程运行完毕

    两个或多个子线程之间的顺序同样如此,

    如果执行顺序限制为 【子线程1 → 子线程2 → 主线程结束】

    public class condition {
    	public static void main(String[] args) {
    		
    		MyThread t1 = new MyThread("子线程1");
    		MyThread t2 = new MyThread("子线程2");
    		
    		try {
    			t1.start();
    			t1.join();//join()方法只有在调用start()方法后使用才有意义
    			t2.start();
    			t2.join();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("主线程结束");
    	}
    }
    
    class MyThread extends Thread {
    	
    	public MyThread(String string) {
    		this.setName(string);
    	}
    
    	@Override
    	public void run(){
    		for(int i=0;i<5;i++) {
    			System.out.println(i+"["+this.getName()+"]");
    		}
    	}
    }
    
    

     结果为:

    0[子线程1]
    1[子线程1]
    2[子线程1]
    3[子线程1]
    4[子线程1]
    0[子线程2]
    1[子线程2]
    2[子线程2]
    3[子线程2]
    4[子线程2]
    主线程结束
    View Code

    参考:https://www.cnblogs.com/songshu120/p/7966314.html(多线程创建的三种方式)

  • 相关阅读:
    c# 无边框窗体显示任务栏菜单(系统菜单)
    C# 任务栏的相关信息
    C# 获取屏幕尺寸
    C# winform 中的Form 源码
    C# datagridview 的属性及事件
    C# datagridview 中添加下拉框,并绑定selectedindexchanged事件
    C# 键盘事件
    Struts2的国际化
    Struts2类型转换器
    Struts2的运行流程以及关键拦截器介绍
  • 原文地址:https://www.cnblogs.com/tubybassoon/p/9692964.html
Copyright © 2011-2022 走看看