多线程(个人学习笔记)

程序:序指的是为完成某种任务,用某种语言编写的一组指令的集合。

进程:进程指的是程序的一次执行过程,或者是正在运行的一个程序,也就是说当一个程序被
        运行,就开启了一个进程,
线程:进程可以进一步细化为线程,是一个程序内部执行的一条路径,也就是说一个进程可以
        有多个线程,一个线程就是一个指令流,cpu 调度的最小单位,由 cpu 一条一条执行指令,
        每个线程拥有独立的线程栈和程序计数器。如果一个进程同时执行多个线程,那么就是多线
        程。例如我们打开某个软件然后同时使用该软件里的两个功能,这也叫多线程。
并行:多个 cpu 同时执行多个任务。
并发:一个 cpu 同时执行多个任务。
多线程的创建:
        1.继承Tread类:class类extendsThread{
                    public void run(){
                //Thread类提供了一个静态方法名字叫做getname()用于获取线程名
                        线程要执行的任务必须放在该方法里面
                        }

                    }
                    类 对象名 =new 类
                    对象名.start//用于开启一个线程

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Dome1 {
    public static void main(String[] args) {
        MyThread1 my1=new MyThread1("THIS1");
        MyThread1 my2=new MyThread1("THIS2");
        my1.start();
        my2.start();
    }
}
class MyThread1 extends Thread{
    public static Lock l=new ReentrantLock();
    public MyThread1(){

    }
    public MyThread1(String name){
        super(name);
    }
    public void run(){
        l.lock();
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"-------"+i);
        }
        l.unlock();
    }
}


                run方法和start方法区别start方法只能调用一次,run方法里面存放的是线程任务
        2.实现Runable接口
    class 线程类 implements Runable{
        public void run(){
            线程任务
        }
    
    }
线程类 线程对象 =new 线程类
Thread thread=new thread()
thread.start()
继承 Thread 类和实现 Runable 接口都可以去创建线程,这二者实际上并没有可比性, 它们只是接口和类的区别,同时也是继承关系。

我们通过继承 Thread 类去创建线程的时候需要注意的是 Thread 的实现类里面的 run 方 法只是定义了线程需要执行的任务,如果直接调用 run 方法就相当于在主线程 main 中调用 一个类的普通的方法,并不会重新开启一个线程。

public class Titck {
    public static void main(String[] args) {
        WindowSal sal = new WindowSal();
        Thread thread1 = new Thread(sal,"窗口一");
        Thread thread2 = new Thread(sal,"窗口二");
        Thread thread3 = new Thread(sal,"窗口三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class WindowSal implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            sal();
        }
    }
    private synchronized void sal(){
        if (ticket > 0){
            System.out.println(Thread.currentThread().getName()+"正在售卖第"
                    +(1000-ticket+1)+"张票"+"还剩下:"+(ticket-1)+"张票。");
                    ticket--;
        }else {
            Thread.currentThread().stop();
        }
    }
}


3.实现Callable接口

Callable 类型线程是通过 FeatureTask 类来实现的,而 FeatureTask 是 Feature 接口的一个实现类,我们还可以通过 FeatureTask 中 get 方法去获 取 call 方法中的返回值。

        FeatureTask 类它实现了 RunnableFuture,然后 RunableFuture 又实现了 Runnable, 和         Future,因此 FeatureTask 也能处理 Runable 类型任务。

Callable 和 Thread 类、Runable 接口一样都是创建线程的方式,其中 Thread 类和 Runable 接口通过 run 方法实现线程的任务,Callable 接口通过 callable 方法实现线程的任务,并且 callable 方法是有返回值的

4.线程池
线程的调度:cpu会给线程分配时间片,一旦得到了时间片,他就可以执行,
哪个线程抢到时间碎片,那么该线程就执行,没有抢到时间碎片的线程机会处于一个等待状态

 

线程的生命周期:

⚫ 新建:当一个 Thread 类或其子类被创建声明后,新生的线程对象就处于新建状态。

⚫ 就绪:当处于新建状态的线程对象调用 start 方法以后,它就进入线程队列等待 cpu 时间片,此时线程对象已经具备了运行条件,只是没有得到 cpu 资源。

⚫ 运行:处于就绪状态的线程对象获得 cpu 资源以后就可以进入运行状态,run 方法 定义了线程的任务。

⚫ 阻塞:在某些特殊情况下,被人为挂起或执行输入输出操作的时候,线程对象让出 自己的 cpu 并终止任务进入阻塞状态。

⚫ 死亡:线程对象完成了它的线程任务或者被强制退出、发生异常等,线程对象就进 入死亡状态。
Thread的几个常用方法:
1.运行状态--》阻塞---》就绪
sleep()可以让当前线程休眠,知道休眠时间结束才让当前新城重新去竞争cpu时间片
join()插队
wait() 等待   
yield()可以让一个线程从运行状态回归到就绪状态
    yield()可以让当前线程释放时间碎片,进入就绪状态重新等待时间碎片
线程安全:

1.使用线程安全
2.synchronized:在java中就是一个对象
        假如一个对象最先拿到锁,拿到锁之后他就会进入代码运行,并且代码锁住,别的对象不可调用
synchronized(对象){
    代码块    
}//对象:对象.class


同步代码块就是将需要的代码装载在代码块里面
同步方法就是在方法上面加上一个synchronized关键字

synchronized 的作用即线程的
1.原子性2.有序型3.可见性
死锁:锁不释放并开始抢占,死锁原因(加锁顺序不当)
解决死锁:

1.改变加锁顺序

2.使用lock锁(手动锁:自己加锁自己释放锁)
 

3.lock:手动锁 :lock()上锁 unlock()解锁trylock()
 

trylock():和lock()方法一样也是用于加锁,只是他有返回值;
            若枷锁成功返回true否则返回flase
            需要注意的是若是加锁失败则不能去unlock解锁
trylock(long time,timeUnit unit):trylock类似,只是该方法加入了时间,
                即规定时间内加锁成功就返回ture,否则返回flase
                该方法会抛出一个异常即Int
lock和synchronized区分:
        1.synchronized是关键字,lock是接口
        2.synchronized的加锁和释放锁是自动的lock则相反
        3.lock可以监听到锁的状态
        4.synchronized会造成死锁lock不会
利用wat(),join(),sleep()等方法去实现线程之间的一个交互
wati()和notify()配合使用可以完成线程间的一个通讯
T1和T2让他们交替打印数字1-20

Volatile:Volatile 不能保证代码的原子性,但是可以保证可见性和有序性(禁止代码重 排)。还需要注意的是 Volatile 只能修饰变量


notify()----用于唤醒另外一个被wait的线程
wati()----用于将当前线程进入阻塞状态,并释放锁
//wait()要抛出一个异常
wait和notify必须放在synchronized同步方法或者代码块里面
通过锁对象去调用wait和notify方法
notifyall()和notify
1.notify用于唤醒一个线程
2.notify用于唤醒所有个线程
wait和sleep的区别
sleep不会释放锁wait会释放锁
sleep自动唤醒,wait需要配合notify手动唤醒


callable:
    FutureTask可以用于接受callable对象
    FutureTask还提供了一个方法get----用于拿取返回值
    由于FutureTask实现了Runnable接口,对此它也是Runnable的一个实例对象
Callable 接口通过 callable 方法实现线程的任务,并且 callable 方法是有返回值的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值