文章目录
这是我在学习疯狂Java讲义期间的笔记,如有错误请指出。
一、问题提出:
(一)、单线程与多线程的区别?
- 单线程只有一条顺序执行流;多线程可以有多条顺序执行流,并且多天顺序执行流互不干扰。
- 单线程需要完成当前事件后才能执行下一事件;多线程可以同时执行多件事情。
(二)、进程与线程的区别?
进程:
- 进程= 程序代码 + 数据 + PCB;
- 并发型: 多个进程可以在单处理器并发执行;
线程:
- 同一个进程可以并发处理多个任务;
- 线程是进程的执行单位;
- 一个线程可以创建和撤销另一个线程;
- 共享内存、文件句柄和其它每个进程应有状态,线程可以拥有自己的堆栈、程序计数器和局部变量。
二、线程的创建和启动
(一)、继承Thread类创建线程类
public class FirstThread extends Thread
{
private int i ;
// 重写run方法,run方法的方法体就是线程执行体
public void run()
{
for ( ; i < 10 ; i++ )
{
// 当线程类继承Thread类时,直接使用this即可获取当前线程
// Thread对象的getName()返回当前该线程的名字
// 因此可以直接调用getName()方法返回当前线程的名
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
// 调用Thread的currentThread方法获取当前线程
System.out.println(Thread.currentThread().getName()
+ " " + i);
if (i == 5)
{
// 创建、并启动第一条线程
new FirstThread().start();
// 创建、并启动第二条线程
new FirstThread().start();
}
}
}
}
执行结果
main 0
main 1
main 2
main 3
main 4
main 5
Thread-0 0
Thread-0 1
main 6
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
main 7
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
main 8
main 9
每次执行结果不同;输出 i 的值不连续,因为每次创建线程对象时都需要创建一个FirstThread对象,所以Thread-0和Thread-1不能共享该实例变量i。使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量
(二)、继承Runnable接口创建线程类
public class SecondThread implements Runnable
{
private int i ;
// run方法同样是线程执行体
public void run()
{
for ( ; i < 10 ; i++ )
{
// 当线程类实现Runnable接口时,
// 如果想获取当前线程,只能用Thread.currentThread()方法。
System.out.println(Thread.currentThread().getName()
+ " " + i);
}
}
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
System.out.println(Thread.currentThread().getName()
+ " " + i);
if (i == 5)
{
SecondThread st = new SecondThread(); // ①
// 通过new Thread(target , name)方法创建新线程
new Thread(st).start();
new Thread(st , "新线程2").start();
}
}
}
}
执行结果
main 0
main 1
main 2
main 3
main 4
main 5
Thread-0 0
Thread-0 1
Thread-0 2
新线程2 2
Thread-0 3
新线程2 4
Thread-0 5
新线程2 6
Thread-0 7
新线程2 8
Thread-0 9
main 6
main 7
main 8
main 9
(三)、使用Callable 和Future创建线程
Thread类的作用是把run()方法包装程线程执行体,但Java目前不能直接把任意方法都包装成线程执行体。
Callable提供call()可作为线程执行体,call()功能比run()强大。Callable对象不能直接作为Thread的target,并且call()拥有返回值——call()方法不能直接调用,他作为线程执行体被调用。Future接口代表Callabel接口里call()方法的返回值,并为Future 接口提供FutureTassk实现类,该实现类实现Future接口,并实现Runnable接口——可作为Thread类的target。
public class ThirdThread
{
public static void main(String[] args)
{
// 创建Callable对象
ThirdThread rt = new ThirdThread();
// 先使用Lambda表达式创建Callable<Integer>对象
// 使用FutureTask来包装Callable对象
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
int i = 0;
for ( ; i < 10 ; i++ )
{
System.out.println(Thread.currentThread().getName()
+ " 的循环变量i的值:" + i);
}
// call()方法可以有返回值
return i;
});
for (int i = 0 ; i < 10 ; i++)
{
System.out.println(Thread.currentThread().getName()
+ " 的循环变量i的值:" + i);
if (i == 5)
{
// 实质还是以Callable对象来创建、并启动线程
new Thread(task , "有返回值的线程").start();
}
}
try
{
// 获取线程返回值
System.out.println("子线程的返回值:" + task.get());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
执行结果
main 的循环变量i的值:0
main 的循环变量i的值:1
main 的循环变量i的值:2
main 的循环变量i的值:3
main 的循环变量i的值:4
main 的循环变量i的值:5
main 的循环变量i的值:6
main 的循环变量i的值:7
main 的循环变量i的值:8
main 的循环变量i的值:9
有返回值的线程 的循环变量i的值:0
有返回值的线程 的循环变量i的值:1
有返回值的线程 的循环变量i的值:2
有返回值的线程 的循环变量i的值:3
有返回值的线程 的循环变量i的值:4
有返回值的线程 的循环变量i的值:5
有返回值的线程 的循环变量i的值:6
有返回值的线程 的循环变量i的值:7
有返回值的线程 的循环变量i的值:8
有返回值的线程 的循环变量i的值:9
子线程的返回值:10