StackTraceElement[] stacks = current.getStackTrace(); for (int i = 0; i < stacks.length; i++) { System.out.println(stacks[i]); }
另外,在调试的时候,可以直接输出当前线程的堆栈信息:
Thread.dumpStack();
注意不要混淆:
演示:
Thread.currentThread().getName()
runnable是没有返回值的。
如果我们希望获得新线程方法运行后的返回值,需要:
Callable<Integer> getAge = ()-> 23; FutureTask<Integer> ft = new FutureTask<>(getAge); new Thread(ft).start(); //不要忘了调用start()启动新线程最后,调用get()方法获得结果:
System.out.println(ft.get());
上述get()方法是线程阻塞的,即:每次执行get()方法,都会让线程停下来等待运行结果。
for (i = 0; i < 10; i++) { Callable<Integer> getAge = ()-> { System.out.println(Thread.currentThread().getId() + "-" + i); return i; } ; FutureTask<Integer> ft = new FutureTask<>(getAge); new Thread(ft).start(); //不要忘了调用start()启动新线程 System.out.println(ft.get()); //阻塞
演示:上述代码运行之后会形成类似于“同步”的结果
这样不利于发挥多线程异步并发的优势,所以Java 8开始,推出了非阻塞的CompletableFuture:
CompletableFuture<Integer> cf = CompletableFuture .supplyAsync(() -> { System.out.println( Thread.currentThread().getId() + "-" + i); return i; }); //cf运行完成之后会执行该lambda表达式 //r代表cf的运行结果 cf.thenAccept(r -> { System.out.println(Thread.currentThread().getId() + "*" + r); }); System.out.println("-------------");演示:没有阻塞出现,结果又“乱七八糟”了,^_^
我们可以声明一个类继承自Thread,重写run()方法
class greet extends Thread{ @Override public void run() {
此后,调用该类实例对象的start()方法时,就会开启一个新线程,在新线程中运行其run()方法。
但我们不推荐这种方法,首先是有点怪异,其次是不能很方便的让线程返回一个值。
@想一想@:能不能这样?
在Thread子类里面:
public int age; public void run() { age = 23;然后,在外面这样调用:
greet r = new greet(); r.start(); System.out.println(r.age);不行的!因为多线程的异步执行。
synchronized还可以直接修饰方法,之前的写法可以直接写成:
public synchronized void run() { i = 0;
虽然synchronized标注在方法前面,但锁住的仍然是当前对象。
方法还可以是静态的,比如:
public synchronized static void recover() {这时候,锁住的是整个类,等同于:
public static void recover() { synchronized (Student.class) {
本质上,类锁还是由对象锁实现的(*.class仍然是一个对象)。且JVM中类对象始终只有一个,所以类锁会阻塞所有视图通过类来访问当前资源的线程。
但类锁不影响对象锁。
在Object中还定义了两个方法。但这两个方法不是任何类都可以调用的,
演示:运行报错:
必须在 synchronized 块中才能调用wait()和notify()方法。因为:
public void run() { synchronized (this) { // 锁住了当前对象 System.out.println("before wait"); this.wait(); System.out.println("after wait");
public synchronized void recover() { this.notify();
Student atai = new Student(); Thread thread = new Thread(atai); thread.start(); System.out.println("--------"); //atai.recover();对比演示:假如不调用recover
对比sleep()和join():
首先创建了一个固定长度为5的线程池
ExecutorService service = Executors.newFixedThreadPool(5);
然后就可以用service调用execute()方法:
for (i = 0; i < 10; i++) { service.execute(()->{ System.out.println(Thread.currentThread().getId()+ ":" +i); }); }
Executors是一个线程池工厂,提供了很多的工厂方法,可以创建的线程池包括:
演示:不同的线程池使用了不同的线程……
如果要执行的是有返回值的方法,就需要:
Future<Integer> task = service.submit(()->{ System.out.println(Thread.currentThread().getId()+ ":" +i); return i; });再调用task.get()方法,就能拿到运行结果。
一次性的、并发的使用多个线程,执行多个任务。
多个任务用Collection<? extends Callable<T>> tasks封装:
Collection<Callable<String>> tasks = new ArrayList<>(); tasks.add(()->"源栈欢迎你"); tasks.add(()->"大神小班,拎包入住");invokeAll:执行所有方法,返回Future列表:
List<Future<String>> fs = service.invokeAll(tasks);invokeAny:执行任意一个callable,返回其结果:
String any = service.invokeAny(tasks);
多快好省!前端后端,线上线下,名师精讲
更多了解 加: