目录
创建线程的第一种方法:extends Thread 并重写run()
方法一:通过Thread.currentThread()和set,get方法
创建线程的第三种方法:implements Callable重写call()
程序,线程,进程的概念
程序:是为了完成特定任务、用某种语言编写的一组指令的集合,是一段静态代码。(程序是静态的)
进程(process):是程序的一次执行过程,正在运行的一个程序,进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域。(进程是动态的)是一个懂得过程。进程的生命周期:有他自身的产生,存在和消亡的过程
线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径。若一个进程同一时间并行执行多个线程,就支持多线程。
---------------------------------------------------------------------------------------------------------------------------------
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
例子:
360杀毒软件(程序)--->启动杀毒、木马查杀、清理垃圾(三个线程同时进行)--->电脑体检进程(一个进程包含了三个线程)
创建线程的第一种方法:extends Thread 并重写run()
// 方法一:extends Thread后重写run()
public class ThreadTest1 extends Thread{
@Override
public void run(){
// 输出1-10
for (int i = 0; i <= 10; i++) {
System.out.println("thread/run:" + i);
}
}
}
@Test
public void test01(){
ThreadTest1 tt = new ThreadTest1();
//tt.run(); // 这个方法不能直接实用,会被当成TT1类中的普通方法
tt.start();// start()是Thread中的,运行这个方法才是开启线程,完成和主程序抢夺资源的操作
for (int i = 0; i <=10 ; i++) {
System.out.println("test01:" + i);
}
}
结果:成功抢夺了资源
获取当前线程的名字:
方法一:通过Thread.currentThread()和set,get方法
public class ThreadTest1 extends Thread{
@Override
public void run(){
// 输出1-10
for (int i = 0; i <= 10; i++) {
System.out.println(this.getName() + "thread/run:" + i);
}
}
}
@Test
public void test01(){
ThreadTest1 tt = new ThreadTest1();
tt.setName("子线程");// 设置当前子线程的名字
tt.start();
// Thread.currentThread():获取当前线程
Thread.currentThread().setName("主线程");//设置主线程的名字
for (int i = 0; i <=10 ; i++) {
System.out.println(
Thread.currentThread().getName() // 获取当前线程的名字
+ "test01:" + i);
}
}
结果:成功
方法二:通过构造器
// 创建线程的方法一:extends Thread后重写run()
public class ThreadTest1 extends Thread{
public ThreadTest1() {
}
// 获取当前线程的第二种方法:构造器
public ThreadTest1(String name) {
super(name);
}
@Override
public void run(){
// 输出1-10
for (int i = 0; i <= 10; i++) {
System.out.println(this.getName() + "thread/run:" + i);
}
}
}
@Test
public void test02(){
ThreadTest1 tt = new ThreadTest1("子线程");
tt.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i <=10 ; i++) {
System.out.println(
Thread.currentThread().getName() + "test01:" + i);
}
}
经典的买火车票的问题:
public class TicketThread01 extends Thread{
static int ticketNumber = 10;
public TicketThread01() { }
public TicketThread01(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if(ticketNumber > 0){
System.out.println("我在" + this.getName() + "买到了第" + ticketNumber-- +"张票");
}
}
}
}
public static void main(String[] args) {
TicketThread01 tt1 = new TicketThread01("窗口1");
tt1.start();
TicketThread01 tt2 = new TicketThread01("窗口2");
tt2.start();
TicketThread01 tt3 = new TicketThread01("窗口3");
tt3.start();
}
成功(junit测试,该段代码无法运行)
创建线程的第二种方法:实现Runnable接口
public class ThreadTest2 implements Runnable{
@Override
public void run() {
// 输出1-10
for (int i = 0; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "ThreadTest2的run" + i);
}
}
}
@Test
public void test01(){
ThreadTest2 tt = new ThreadTest2();
Thread t = new Thread(tt,"子线程");
t.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "主线程的" + i);
}
}
测试结果:成功
再次重写买火车票
public class TicketThread02 implements Runnable{
// 因为这次测试类中三个线程共用tt对象,所以tn不用static修饰
int ticketNumber = 10;
@Override
public void run() {
for (int i = 1; i <= 100 ; i++) {
if(ticketNumber > 0){
System.out.println("我在" + Thread.currentThread().getName() + "窗口买到第" + ticketNumber-- + "张票");
}
}
}
}
public static void main(String[] args) {
TicketThread02 tt = new TicketThread02();
Thread t1 = new Thread(tt,"窗口1");
t1.start();
Thread t2 = new Thread(tt,"窗口2");
t2.start();
Thread t3 = new Thread(tt,"窗口3");
t3.start();
}
成功,但有时候会出现两次一样的第i张车票,或者是-1,-2这种情况:
线程不安全--->在《线程安全问题》那里解决
创建线程的第三种方法:implements Callable<v>重写call()
该方法特点:1.有返回值,2.抛异常
public class ThreadTest3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return new Random().nextInt(10);
}
}
@Test
public void test01() throws ExecutionException, InterruptedException {
ThreadTest3 tt = new ThreadTest3();
FutureTask<Integer> ft = new FutureTask<>(tt);
Thread t = new Thread(ft);
t.start();
Integer integer = ft.get();
System.out.println(integer);
}
成功
线程的生命周期 ![](https://img-blog.csdnimg.cn/316ad0c435a14640aeec49a1000d5409.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAMzDlsoHnmoRKYXZh54ix5aW96ICF,size_20,color_FFFFFF,t_70,g_se,x_16)