多线程的简单介绍和实现的三种方式

一些概念

1 进程 正在运行的软件
2 单线程 一个进程只有一条执行路径
3 多线程 一个进程有多个执行路径
4 并发 同一时刻,多个指令在单个cpu上交替执行
5 并行 同一时刻 多个指令在多个cpu上同时执行

多线程的实现方式

三种实现方案:
>继承Thread类的方法实现多线程
>实现Runnable接口的方式实现多线程
>利用Callable和Funture接口的方式实现多线程

(1) 继承Thread

1 创建一个类继承Thread
2 重写Thread类的run()方法 (要执行的操作卸载run方法中)

class MyThread extends Thread {
	
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}

3 创建子类对象
4 通过此对象调用start()方法

public class Demo1 {
    public static void main(String[] args) {
    	/*	现在只有1个线程,任何java程序起码有个主线程 main  
			MyThread t1=new MyThread();并不是一个线程
			只是创建了一个线程对象(线程对象和线程还是有很大区别的 
			对象是创建在虚拟机堆空间中的,
			而线程是操作系统维护的一种资源 为什么说Thread对象代表一个线程?
			因为把线程对象创建出来以后,以他为代表才能创建线程,
			我们程序员不能绕开虚拟机工作,不能直接去访问操作系统),
		*/	
     	MyThread t1=new MyThread();
		MyThread t2=new MyThread();
        //通过此对象调用start方法 : ①启动当前线程,② 调用当前线程的run()方法
        //start() 线程对象会帮你到操作系统中发出申请能不能为我创建一个线程 
        //如果得到批准操作系统就创建一个新线程
		//这才是创建线程 或者是启动线程
        t1.start();
        //这句话是在主线程中执行的
        System.out.println("你好世界");
        t2.start();
        System.out.println("hello world");
    }
}    
//cup的切换是随机的 所以看到的结果每次是不一样的

run()和start()方法的区别?
如果直接调用run()方法,表示的仅仅是创建对象,用对象去调用方法,并没有开启线程
相当于是普通方法的调用
start():表示启动线程,然后由jvm调用此线程的run()方法

注意点:
(1)不能直接调用run方法的方式启动线程
(2)不能同一个线程启动两次 如果想启动两个线程就只能创建一个新的线程对象

(2)实现Runnable接口

1 创建一个类实现Runnable接口
2 重写run()方法

class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName()+"-"+i);
        }
    }
}

3 创建此类的对象
4 创建Thread类的对象并以此类的对象作为构造参数
5 通过Thread类的对象调用start()方法

public class Demo1 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread,"线程一");
        thread1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"-"+i);
        }

        //如何再启动一个线程
        Thread thread2 = new Thread(myThread);
        thread2.setName("线程二");
        thread2.start();

    }
}

原码分析

1 使用的是 Thread中的start()方法 该方法会调用Thread类中的run()方法
Thread类中的run()原码:

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

如果target 不等于空就是调用 target中的run()方法
private Runnable target;//发现target是Runnable类型的

再看Thread thread1 = new Thread(myThread,"线程一"); 构造方法
//把咱自己写的MyThread对象也就是Runnable类的实现类赋值给了target  
public Thread(Runnable target, String name) {
    this(null, target, name, 0);
}

现在target不为null 调用target.run(); 实际会找咱重写的run方法

(3)实现callable接口

1 创建一个实现了callable接口的实现类
2 重写call() 方法 执行的错做写在其中

class MyThread implements Callable{
    @Override
    public Object call() throws Exception {
        int  num=0;
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
            num+=i;
        }
        return num;
    }
}

3 创建实现callable 接口的实现类对象
4 将实现的类对象作为参数传递到FutureTask构造器中
5 将FutureTask对象作为参数传递到Thread类的对象的构造器中,启动线程
6 可以获取call方法的返回值

   
public class Demo2 {
    public static void main(String[] args) {
        //需要执行call方法
        MyThread my =new MyThread();
        //可以获取线程执行完毕的结果,也可以作为参数传递给Thread
        FutureTask futureTask=new FutureTask(my);
        //启动线程
        new Thread(futureTask).start();
        try {
         //get();
         //返回值即为FutureTask构造方法参callable实现类重写的call()方法的返回值
            Object num = futureTask.get();
            System.out.println(num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

开发中优先选择实现Runnable接口的方式
1 实现的方式没有类的单继承的限制
2 实现的方式更适合处理多个线程有共享数据的情况

联系:
Thread 实现了Runnable接口 重写了run()方法
在继承Thread类的时候 我们重写的实际上是Thread类重写的Runnable的run()方法
//我重写了你的重写

相同:都需要重写Run()方法

Thread的一些方法

(1)获取线程名字

    //返回此线程的名称。  线程有默认的名字 格式 Thread-编号
	public final String getName();

(2)设置线程名字

	//将此线程的名称更改为等于参数name 。
	public final void setName(String name)
	
	//通过构造设置名字
	public Thread(String name)
代码实现
public class Demo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, ExecutionException, InterruptedException {
        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread("线程2");
        m1.setName("线程1");
        //m2.setName("线程2");
        m1.start();
        m2.start();
        System.out.println(m1.getName());
        System.out.println(m2.getName());
    }
}
class MyThread extends Thread {
    public MyThread() {
    }
    //子类不能继承父类的有参构造  需要通过super(有参)调用父类的构造方法
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"  "+i);
        }
    }
}

(3)获取多线程对象

Thread 中静态方法
//返回对当前正在执行的线程对象的引用。 结果就是当前正在执行的线程。
public static Thread currentThread()   
    
Thread.currentThread().getName() 获取当前线程的名字 默认名(Thread-0/1/2...)
Thread.currentThread().setName() 设置当前线程的名字  

public static void main(String[] args) {
    //获取主线程名字
    System.out.println(Thread.currentThread().getName());
    //给主线程是指名字
    Thread.currentThread().setName("主线程");
    System.out.println(Thread.currentThread().getName());

}

(4)sleep

// 1秒=1000毫秒
//使当前正在执行的线程停留(暂停执行)指定的毫秒数,这取决于系统定时器和调度程序的精度和准确性。
//线程不会丢失任何显示器的所有权。
//millis - 以毫秒为单位的睡眠时间长度 不能是负数 否则报错
//通俗说法
:让当前线程睡眠指定的m毫秒数,在指定的m毫秒时间内当前线程是阻塞状态
public static void sleep(long millis)

//导致正在执行的线程以指定的毫秒数加上指定的纳秒数来暂停(临时停止执行),
//这取决于系统定时器和调度器的精度和准确性。 线程不会丢失任何显示器的所有权。 
//millis - 以毫秒为单位的睡眠时间长度 
//nanos - 0-999999额外的纳秒睡眠 
public static void sleep(long millis,int nanos) 
    
public class Demo1 {
    public static void main(String[] args) throws InterruptedException 	   {
        MyThread thread = new MyThread("线程一");
        thread.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" 			+ i);
            try {
                this.sleep(1000);//阻塞1秒 
             //Thread类中run方法没有抛异常 那么重写的方法也不能抛异常只能自己处理
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public MyThread(String name) {
        super(name);
    }
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值