Java多线程学习总结--线程概述及创建线程的方式(1)
在Java开发中,多线程是很常用的,用得好的话,可以提高程序的性能。
首先先来看一下线程和进程的区别:
1,一个应用程序就是一个进程,一个进程中有一个或多个线程。一个进程至少要有一个主线程。线程可以看做是轻量级的进程。(lightweight process)
2,多个线程可以共享进程的资源。进程之间是独立的,一个进程不能共享其它进程的资源。
3,因为系统创建进程需要为其分配空间,所以创建进程的代价高,创建线程的代价则要小得多。
创建线程的方式:
Java中创建多线程有3中方式:
1,继承Thread类。
一个类继承Thread类并且重写了run方法之后,如果新建这个类的实例,并调用start方法,那么系统就会启动一个新线程,并执行run方法。代码如下:
1 public class ThreadApp { 2 public static void main(String[] args){ 3 // 创建线程 4 MyThread thread = new MyThread(); 5 // 启动线程 6 thread.start(); 7 } 8 } 9 10 11 class MyThread extends Thread { 12 13 private int i = 0; 14 15 public void run() { 16 for (; i < 5; i++) { 17 System.out.println(getName() + ":" + i); 18 } 19 } 20 }
2,实现Runnable接口。
定义一个类实现Runnable接口,然后创建该类的实例,然后创建Thread对象,将Runnable实例作为Thread对象的target,最后调用Thread对象的start方法。在执行是,Thread对象会调用Runnable对象的run方法。代码如下:
public class ThreadApp { public static void main(String[] args) { // 创建runnable对象 MyRunnable target = new MyRunnable(); // 创建thread对象,并将runnable作为thread的target Thread thread = new Thread(target); // 调用thread的start方法,在线程执行时,会调用target的run方法 thread.start(); } } class MyRunnable implements Runnable { private int i = 0; @Override public void run() { while (i < 500) { synchronized (this) { System.out .println(Thread.currentThread().getName() + ":" + i++); } } } }
3,实现Callable接口。
Callable是一个泛型接口,这种创建多线程的方式可以获得线程的执行后的返回值。创建步骤为:定义一个类MyCallable实现Callable接口,创建MyCallable的实例,然后创建FutureTask对象target来包装Callable对象,因为FutureTask类实现了Runnable接口,所以可以作为Thread的target属性。最后创建Thread。当线程执行完毕之后,调用FutureTask的get方法获取的返回值。代码如下:
public class ThreadApp { public static void main(String[] args) { // 创建Callable对象 MyCallable callable = new MyCallable(); // 创建FutureTask对象包装callable,FutureTask类实现了Runnable接口,所以可以作为Thread类的target FutureTask<String> target = new FutureTask<>(callable); // 创建线程 Thread thread = new Thread(target); // 启动线程 thread.start(); try { // 获得线程执行结果 String result = target.get(); System.out.println(result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } class MyCallable implements Callable<String> { @Override public String call() throws Exception { synchronized (this) { System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); return new Date().toString(); } } }
三种创建线程方式的比较:
使用Thread创建线程最简单,它有getName()方法可以直接获取当前线程的名称。但是不够灵活。多个线程之间不能共享Thread的属性。
使用Runnable和Callable是一样的,都是先实现这两个接口,然后将实现类的实例作为Thread的target来创建线程。使用Callable接口可以创建带返回值的线程。另外,多个线程之间可以共享target的属性。代码如下:
public class ThreadApp { public static void main(String[] args) { MyRunnable target = new MyRunnable(); // 两个线程使用同一个target,可以共享target中的属性 Thread thread1 = new Thread(target); Thread thread2 = new Thread(target); thread1.start(); thread2.start(); } }
关于多个线程共享资源的问题,在后边的线程通信会有更好的方法。