java 编程思想 多线程学习笔记

java 编程思想 多线程学习笔记

  • 欢迎使用Markdown编辑器
    • 一、如何创建多线程?
    • 总之,在任何线程池中,现有的线程可能的情况都会被复用。
    • 在任务中产生返回值

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

一、如何创建多线程?

1、继承Runnable,把需要多线程运行的程序放到 public void run() 方法里,然后在main方法中 new 一个thread,并在实例化的时候调用start(); 例如如下代码:

在这里插​
public class LiftOff implements Runnable {
	protected int countDown = 10; // Default
	private static int taskCount = 0;
	private final int id = taskCount++; //区分任务的多个实例
	public LiftOff() {}
	public LiftOff(int countDown) {
		this.countDown = countDown;
	}
	public String status() {
		return "#" + id + "(" +
				(countDown > 0 ? countDown : "Liftoff!") + "), ";
	}
	public void run() {
		while(countDown-- > 0) {
			System.out.print(status());
			//是对线程调度器的一种建议,"我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机。"
			Thread.yield();
		}
	}
} ///:~import com.chot.concurrency.LiftOff;
//当main()创建thread对象时,它并没有捕获任何对这些对象的引用。在使用普通对象时,这对与垃圾回收来说是一场公平的游戏,但是在使用thread时,情况就不同了。
//每个thread 都“注册”了它自己,因此确实有一个对它的引用,而且在它的任务退出其run() 并死亡之前,垃圾回收器无法清除它。
// (为何GC 无法将其清除呢? 答:因为有栈帧对其有引用,即有一个指针只想堆中那个由thread创建的object。故无法标记其可清除。)
public class MoreBasicThreads {
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++)
      new Thread(new LiftOff()).start();
    System.out.println("Waiting for LiftOff");
  }
}
​
​入代码片

2、使用Executor
Executor在客户端和任务执行之间提供一个简介层,像是一个中介一样,任务就是在这些中介这里执行的,Executor允许你管理异步任务的执行,不需要显式的管理线程的生命周期。目前项目在使用的就是此种方式。

使用Executor有两种方式

                                  ExecutorService exec = Executors.newCachedThreadPool(); 

                                  ExecutorService exec = Executors.newFixedThreadPool(5);

两种方式孰优孰劣?
fixed 一次性预先执行代价高昂的线程分配。因而可以控制线程的数量。newCachedThreadPool在程序执行的过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程
拿我接触到的项目来说,线程的创总和某些事情会关联起来,即会有时间来驱动来创建线程,所以使用的newCachedThreadPool。

总之,在任何线程池中,现有的线程可能的情况都会被复用。

下面的代码是用Executor来替换moreBasicThreads.java

1、cachedThreadPoll
package com.chot.concurrency.Chap21_2_3;
import com.chot.concurrency.LiftOff;

import java.util.concurrent.*;
// 将morebasicThreads 改造成使用cachedThreadPool
public class CachedThreadPool {
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for(int i = 0; i < 5; i++)
			exec.execute(new LiftOff());
		exec.shutdown();
	}
}
2、指定5个线程数
package com.chot.concurrency.Chap21_2_3;
import com.chot.concurrency.LiftOff;

import java.util.concurrent.*;
// 将morebasicThreads 改造成使用cachedThreadPool
public class CachedThreadPool {
	public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(5);
		for(int i = 0; i < 5; i++)
			exec.execute(new LiftOff());
		exec.shutdown();
	}
}

还有一种 SingleThreadExecutor。这就像是线程数量为1的FixedThreadPool

ExecutorService exec = Executors.newSingleThreadExecutor();

个人认为在debug的时候使用此种方式将使你的focus不会很乱。如果向SingleThreadExecutor提交了多个任务,那么这些任务将排队,每一个任务都会在下一个任务开始之前运行结束。所有的任务将使用相同的线程。

#0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1),#0(Liftoff!)
#1(9), #1(8), #1(7), #1(6), #1(5), #1(4), #1(3), #1(2), #1(1), #1(Liftoff!)
#2(9), #2(8), #2(7), #2(6), #2(5), #2(4), #2(3), #2(2), #2(1), #2(Liftoff!)
#3(9), #3(8), #3(7), #3(6), #3(5), #3(4), #3(3), #3(2), #3(1), #3(Liftoff!)
#4(9), #4(8), #4(7), #4(6), #4(5), #4(4), #4(3), #4(2), #4(1), #4(Liftoff!)

在任务中产生返回值

Runnable是执行工作的独立任务,但是它不返回任何值。如果希望任务在完成时能够返回一个值,那么可以实现Callable接口而不是Runnable接口。
Callable是一个具有类型参数的泛型,他的类型参数表示的是从
call()方法 <而不是run()
> 方法中返回的值。并且必须使用
ExecutorService.submit()**来调用。

你可能感兴趣的:(java)