• Java基础教程——多线程:创建线程


    多线程

    进程

    每一个应用程序在运行时,都会产生至少一个进程(process)。
    进程是操作系统进行“资源分配和调度”的独立单位。

    Windows系统的“任务管理器”可以查看系统的进程,通过Ctrl+Shift+Esc组合键可以调出“任务管理器”。

    进程具有三个特征:

    • 独立性:进程拥有自己独立的资源,有私有的地址空间。
    • 动态性:程序是静态的指令集合,而进程是活动的指令集合,进程有其生命周期。
    • 并发性:多个进程可以在同一个处理器上并发执行,互不影响。虽然同一时刻只能有一个进程执行,但是多个进程被快速轮换执行(时间片轮换算法),宏观上有同时执行的效果(同一时间段内执行)。

    现代的操作系统都支持多进程并发执行。

    线程

    ​ 线程(Thread)是执行特定任务的最小单位,是进程的执行单元,也被称为轻量级进程(Lightweight Process)。
    ​ 一个进程至少有一个线程,也可以有多个线程。所谓多线程就是指同一个进程可以同时并发处理多个任务。

    ​ 线程没有系统资源,多个线程共享其所属进程的系统资源,因此多线程运行时,需要处理好资源同步问题。

    总结:

    • 操作系统可以同时执行多个任务,每个任务是一个进程;
    • 进程可以同时执行多个任务,每个任务是一个线程。

    多线程的优点

    多线程就是下图这种感觉:

    对计算机来说,多线程可以提高CPU的利用率。

    例如:网络的数据传输速率远低于计算机的处理能力,如果是单线程程序,在下载网络资源时,CPU需要花费大量的空闲时间来等待,而多线程能够利用这些空闲时间完成其他任务。

    具体来说:
    |--一个浏览器可以在下载的同时打开其他网页;
    |--Web服务器可以同时相应多个用户请求;
    |--QQ发送文件的时候还能跟其他人继续聊天……

    当前线程

    Thread.currentThread():获取当前线程
    .getName():获取线程名称

    public class TestMainThread {
    	public static void main(String[] args) {
    		// 获得当前运行的线程
    		Thread tMain = Thread.currentThread();
    		// 线程名称,优先级,线程组
    		System.out.println("当前运行的线程是:" + tMain);
    		System.out.println("线程名称:" + tMain.getName());
    	}
    }
    

    当前运行的线程是:Thread[main,5,main]
    线程名称:main


    创建线程

    方法1:继承Thread类

    Thread类代表线程,所有的线程对象都是Thread类或其子类的对象。
    创建线程的步骤:

    1. 继承Thread类
    2. 重写run()方法(线程执行体)
    3. 创建Thread类的实例对象
    4. 调用start()方法启动线程

    可以使用setName(…)为线程设置名字,用getName()获取。
    默认情况下,主线程名为main,子线程名为Thread-0、Thread-1等。

    public class _11NewThread {
    	public static void main(String[] args) {
    		Thread t1 = new MyT();
    		t1.setName("1");
    		t1.start();
    		Thread t2 = new MyT();
    		t2.setName("   2");
    		t2.start();
    	}
    }
    class MyT extends Thread {
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			System.out.println("线程:" + super.getName());
    		}
    	}
    }
    

    方法2:实现Runnable接口

    Runnable是个接口,实现Runnable接口的类还可以继承其它类,这是比方法1优越的地方。

    1. 实现Runable接口
    2. 重写run()方法
    3. 创建Runable对象
    4. 创建Thread对象
    5. 调用thread.start()方法,启动线程

    实际创建的对象还是Thread实例。

    public class _12NewThreadRunnable {
    	public static void main(String[] args) {
    		MyR r1 = new MyR("A");
    		Thread t1 = new Thread(r1);
    		t1.setName("XXX");
    		t1.start();
    		MyR r2 = new MyR("  B");
    		Thread t2 = new Thread(r2);
    		t2.start();
    	}
    }
    class MyR implements Runnable {
    	public MyR(String s) {
    		this.s = s;
    	}
    	private String s;
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			System.out.println("线程:" + s);
    		}
    	}
    }
    
    

    *方法3:实现Callable接口

    使用Callable和FutureTask创建线程——可以获取线程的返回值。这种做法了解即可。

    1. 实现Callable接口的线程,需重写call()方法,有返回值
    2. 需要FutureTask类包装一下Callablle,该类实现了Runable接口
    3. 以Future对象为参数创建线程,调用start()方法启动
    4. 以Futrue对象.get()接收返回值
    package ahjava.p06thread;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    // 实现Callable接口的线程,需重写call()方法,有返回值
    // 需要FutureTask类包装一下Callablle,该类实现了Runable接口
    // 以Future对象为参数创建线程,调用start()方法启动
    // 以Futrue对象.get()接收返回值
    public class _13NewThreadCallable {
    	public static void main(String[] args) {
    		MyCallable _Callable = new MyCallable("A");
    		FutureTask<String> _FutureTask = new FutureTask<>(_Callable);
    		Thread _Thread = new Thread(_FutureTask);
    		_Thread.start();
    		try {
    			// 模拟等待,此过程可看到子线程在执行
    			Thread.sleep(3000);
    		} catch (InterruptedException e1) {
    			e1.printStackTrace();
    		}
    		// 接受子线程的返回值
    		try {
    			String s = _FutureTask.get();
    			System.out.println("子线程的返回值 = " + s);
    		} catch (InterruptedException | ExecutionException e) {
    			e.printStackTrace();
    		}
    	}
    }
    class MyCallable implements Callable<String> {
    	public MyCallable(String s) {
    		this.s = s;
    	}
    	private String s;
    	@Override
    	public String call() throws Exception {
    		for (int i = 0; i < 100; i++) {
    			System.out.println("线程:" + s);
    		}
    		return "我是子线程,已经执行完毕";
    	}
    }
    

    start()和run()

    调用start()是开启新线程,调用run()是普通方法调用。

    方法调用是入栈操作,调用完毕则出栈。
    如果直接调用run()方法,则是在原线程中进行方法调用,用的还是之原线程的栈。
    调用start()才是开启一个新线程,会创建新的栈。


    线程的优先级

    最高 10 Thread.MAX_PRIORITY
    默认 5 Thread.NORM_PRIORITY
    最低 1 Thread.MIN_PRIORITY

    演示示例:

    Thread(Runnable target, String name):为线程直接命名
    Thread.currentThread():获取当前线程

    public class Priority线程优先级 {
    	// *可能不太容易看出来
    	public static void main(String[] args) {
    		MyRu r1 = new MyRu();
    		MyRu r2 = new MyRu();
    		MyRu r3 = new MyRu();
    		Thread t1 = new Thread(r1);
    		// 创建时命名
    		Thread t2 = new Thread(r2, "   B");
    		Thread t3 = new Thread(r3);
    		t1.setName("A");
    		t3.setName("       C");
    		t1.setPriority(Thread.MAX_PRIORITY);
    		t3.setPriority(Thread.MIN_PRIORITY);
    		t1.start();
    		t2.start();
    		t3.start();
    	}
    }
    class MyRu implements Runnable {
    	@Override
    	public void run() {
    		String sName = Thread.currentThread().getName();
    		int sPri = Thread.currentThread().getPriority();
    		for (int i = 0; i < 100; i++) {
    			System.out.println("线程:" + sName + " 优先级:" + sPri);
    		}
    	}
    }
    
    

    多线程的运行结果是不确定的,运行结果每次不同,可能有些时候看不出不同优先级的区别。

  • 相关阅读:
    [转]Linq使用心得——SelectMany替代二重foreach循环
    设计模式—装饰者模式
    设计模式—桥接模式
    iOS_autoLayout_Masonry
    排序算法
    h.264硬件解码
    FFmpegh.264解码
    AAC编解码
    socket UDP简单通讯
    socket TCP简单通讯
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11179234.html
Copyright © 2020-2023  润新知