java学习笔记(14) ---多线程概述

1、什么是进程?
         程序是静止的,运行中的程序就是进程。
         进程的三个特征:
         1.动态性 : 进程是运行中的程序,要动态的占用内存,CPU和网络等资源。
         2.独立性 : 进程与进程之间是相互独立的,彼此有自己的独立内存区域。
         3.并发性 : 假如CPU是单核,同一个时刻其实内存中只有一个进程在被执行。CPU会分时轮询切换依次为每个进程服务,因为切换的速度非常快,给我们的感觉这些进程在同时执行,这就是并发性。
        并行:同一个时刻同时有多个在执行。

   2、什么是线程?
         线程是属于进程的。一个进程可以包含多个线程,这就是多线程。
         线程是进程中的一个独立执行单元。
         线程创建开销相对于进程来说比较小。
         线程也支持“并发性”。

    3、线程的作用:
         可以提高程序的效率,线程也支持并发性,可以有更多机会得到CPU。
         多线程可以解决很多业务模型。
         大型高并发技术的核心技术。
         设计到多线程的开发可能都比较难理解。

4、相关API

        1.public void setName(String name):给当前线程取名字。
        2.public void getName():获取当前线程的名字。
            -- 线程存在默认名称,子线程的默认名称是:Thread-索引。
            -- 主线程的默认名称就是:main
        3.public static Thread currentThread()
            -- 获取当前线程对象,这个代码在哪个线程中,就得到哪个线程对象。
        4、public static void sleep(long time): 让当前线程休眠多少毫秒再继续执行。
        5、通过Thread类的有参数构造器为当前线程对象取名字。(不是API,但写到这了)
        -- public Thread()
        -- public Thread(String name):创建线程对象并取名字。

5、线程的创建方式

(1)直接定义一个类继承线程类Thread,重写run()方法,创建线程对象
            调用线程对象的start()方法启动线程。

        -- 1.定义一个线程类继承Thread类。
        -- 2.重写run()方法
        -- 3.创建一个新的线程对象。
        -- 4.调用线程对象的start()方法启动线程。

        继承Thread类的优缺点:
            优点:编码简单。
            缺点:线程类已经继承了Thread类无法继承其他类了,功能不能通过继承拓展(单继承的局限性)
 

public class _2022112Demo {
    public static void main(String[] args) throws Exception {
        Thread myThread = new MyThread();
        myThread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main线程输出" + i);
        }
    }
}

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

 注意事项:1.线程的启动必须调用start()方法。否则当成普通类处理。
        -- 如果线程直接调用run()方法,相当于变成了普通类的执行,此时将只有主线程在执行他们!
        -- start()方法底层其实是给CPU注册当前线程,并且触发run()方法执行
    2.建议线程先创建子线程,主线程的任务放在之后。否则主线程永远是先执行完!
(2)定义一个线程任务类实现Runnable接口,重写run()方法,创建线程任务对象,把线程任务对象包装成线程对象, 调用线程对象的start()方法启动线程。
          -- 1.创建一个线程任务类实现Runnable接口。
          -- 2.重写run()方法
          -- 3.创建一个线程任务对象。
          -- 4.把线程任务对象包装成线程对象
          -- 5.调用线程对象的start()方法启动线程。
     Thread的构造器:
          -- public Thread(){}
          -- public Thread(String name){}
          -- public Thread(Runnable target){}
          -- public Thread(Runnable target,String name){}
     实现Runnable接口创建线程的优缺点:
          缺点:代码复杂一点。
          优点:
            -- 线程任务类只是实现了Runnable接口,可以继续继承其他类,而且可以继续实现其他接口(避免了单继承的局限性)
            -- 同一个线程任务对象可以被包装成多个线程对象
            -- 适合多个多个线程去共享同一个资源(后面内容)
            -- 实现解耦操作,线程任务代码可以被多个线程共享,线程任务代码和线程独立。
            -- 线程池可以放入实现Runable或Callable线程任务对象。(后面了解)
               注意:其实Thread类本身也是实现了Runnable接口的。
            -- 不能直接得到线程执行的结果!

public class _2022112Demo {
    public static void main(String[] args) throws Exception {
//       Runnable myRunnable = new MyRunnable();
//       Thread t1 = new Thread(myRunnable, "许嵩");
//       t1.start();
        
        // 上下这两种方法都行,只不过一种是另一种的简化罢了
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "子线程输出" + i);
                }
            }
        };
        Thread t2 = new Thread(myRunnable, "许嵩");
        t2.start();

       Thread.currentThread().setName("主线程");
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "线程输出" + i);
        }
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "子线程输出" + i);
        }
    }
}

 (3)实现Callable接口(要是需要得到线程的返回结果,可以用这个)
          -- 1,定义一个线程任务类实现Callable接口 , 申明线程执行的结果类型。
          -- 2,重写线程任务类的call方法,这个方法可以直接返回执行的结果。
          -- 3,创建一个Callable的线程任务对象。
          -- 4,把Callable的线程任务对象包装成一个未来任务对象。
          -- 5.把未来任务对象包装成线程对象。
          -- 6.调用线程的start()方法启动线程
      优缺点:
          优点:全是优点。
             -- 线程任务类只是实现了Callable接口,可以继续继承其他类,而且可以继续实现其他接口(避免了单继承的局限性)
             -- 同一个线程任务对象可以被包装成多个线程对象
             -- 适合多个多个线程去共享同一个资源(后面内容)
             -- 实现解耦操作,线程任务代码可以被多个线程共享,线程任务代码和线程独立。
             -- 线程池可以放入实现Runable或Callable线程任务对象。(后面了解)
             -- 能直接得到线程执行的结果!
          缺点:编码复杂。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class _2022112Demo {
    public static void main(String[] args) throws Exception {
        Callable<String> callable = new MyCallable();
        FutureTask<String> task = new FutureTask<>(callable);
        Thread t = new Thread(task);
        t.start();

       Thread.currentThread().setName("主线程");
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "线程输出" + i);
        }

        try {
            System.out.println(task.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "我可以得到返回结果";
    }
}

6、线程安全问题:多个线程同时操作同一个共享资源的时候可能会出现线程安全问题。

    线程同步的作用:就是为了解决线程安全问题的方案。
    线程同步解决线程安全问题的核心思想:
            让多个线程实现先后依次访问共享资源,这样就解决了安全问题。
    线程同步的做法:加锁
            是把共享资源进行上锁,每次只能一个线程进入访问完毕以后,其他线程才能进来。
    线程同步的方式有三种
        (1)同步代码块
        作用:把出现线程安全问题的核心代码给上锁,每次只能一个线程进入
              执行完毕以后自动解锁,其他线程才可以进来执行。
        格式:
              synchronized(锁对象){
                    // 访问共享资源的核心代码
              }
              锁对象:理论上可以是任意的“唯一”对象即可。
              原则上:锁对象建议使用共享资源。
                    -- 在实例方法中建议用this作为锁对象。此时this正好是共享资源!必须代码高度面向对象
                    -- 在静态方法中建议用类名.class字节码作为锁对象。


        (2)同步方法
        作用:把出现线程安全问题的核心方法给锁起来,
             每次只能一个线程进入访问,其他线程必须在方法外面等待。
        用法:直接给方法加上一个修饰符 synchronized.
        原理:  同步方法的原理和同步代码块的底层原理其实是完全一样的,只是
              同步方法是把整个方法的代码都锁起来的。
              同步方法其实底层也是有锁对象的:
                  如果方法是实例方法:同步方法默认用this作为的锁对象。
                  如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
(3)lock显示锁
java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,
        同步代码块/同步方法具有的功能Lock都有,除此之外更强大

        Lock锁也称同步锁,加锁与释放锁方法化了,如下:
             - `public void lock() `:加同步锁。
             - `public void unlock()`:释放同步锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值