1.继承Thread类
Thread类中的start和run方法的区别?
(1)通过调用线程类的start()方法来启动一个线程,使线程处于就绪状态,即可以被JVM来调度执行,在调度过程中,JVM通过调用线程类的run()方法来完成实际的业务逻辑,当run()方法结束后,此线程就会终止。
(2)如果直接调用线程类的run()方法,会被当作一个普通的函数调用,程序中仍然只有主线程这一个线程。即start()方法能够异步的调用run()方法,但是直接调用run()方法却是同步的,无法达到多线程的目的。
因此,只有通过调用线程类的start()方法才能达到多线程的目的。
例子:
public class MyThread extends Thread {
public MyThread() {}
public MyThread(String name) {
super(name);
}
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName() + ":" +
Thread.currentThread().getId() + "正在运行.");
}
}
}
public class TestMyThread {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("一号线程");
MyThread myThread2 = new MyThread("二号线程");
myThread1.start();
myThread2.start();
while(true) {
System.out.println("主线程。。");
}
}
}
2.实现Runnable接口
例子:
public class MyThread implements Runnable {
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName() + ":" +
Thread.currentThread().getId() + "正在运行.");
}
}
}
public class TestMyThread {
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
Thread thread1 = new Thread(myThread1, "线程一号");
Thread thread2 = new Thread(myThread2, "线程二号");
thread1.start();
thread2.start();
}
}
3.实现Callable接口(带有返回值)
通过FutureTask类的get()方法获取返回值
例子:
public class MyThread implements Callable<Integer> {
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
Thread.sleep(10);
}
return sum;
}
}
public class TestMyThread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
FutureTask<Integer> task1 = new FutureTask<>(myThread1);
FutureTask<Integer> task2 = new FutureTask<>(myThread2);
Thread thread1 = new Thread(task1, "线程1任务");
Thread thread2 = new Thread(task2, "线程2任务");
thread1.start();
thread2.start();
// 该行代码会阻塞,为什么?因为线程执行需要时间,等待线程执行完成才能获取到它的返回值
Integer res1 = task1.get();
Integer res2 = task2.get();
System.out.println(res1);
System.out.println(res2);
System.out.println("。。。。。。。。。。。。。。。");
}
}
4.通过线程池创建
例子:
线程类:
public class MyThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1. 单个的线程池
public void testSingletonPool() throws IOException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Thread(new MyThread(), "线程1"));
executorService.execute(new Thread(new MyThread(), "线程2"));
executorService.execute(new Thread(new MyThread(), "线程3"));
System.in.read();
}
2. 固定数量的
public void testFixedPool() throws IOException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new Thread(new MyThread(), "线程1"));
executorService.execute(new Thread(new MyThread(), "线程2"));
executorService.execute(new Thread(new MyThread(), "线程3"));
System.in.read();
}
3. 不固定数量,缓存数量的线程池,最大是Integer.max的值
public void testCachePool() throws IOException, InterruptedException {
// 线程池1个都不放,如果有一个任务了,就创建一个。
// 如果被创建的这个线程在执行中的时候,有第二个任务, 那么会创建第二个线程对象执行
// 如果第一个执行完了, 第二个任务过来,就不会创建新的线程对象
// 以此类推
ExecutorService executorService = Executors.newCachedThreadPool();
while(true) {
executorService.execute(new Thread(new MyThread(), "线程1"));
Thread.sleep(10);
}
}
4. 周期任务线程池
public void testSchedulePool() throws IOException {
MyThread myThread = new MyThread();
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// ScheduledFuture<?> schedule = scheduledExecutorService.
// schedule(myThread, 1000, TimeUnit.MILLISECONDS);
ScheduledFuture<?> scheduledFuture = scheduledExecutorService.
scheduleAtFixedRate(myThread, 5000, 2000, TimeUnit.MILLISECONDS);
System.in.read();
}