继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java多线程初学者笔记

xiaoxin3839519
关注TA
已关注
手记 23
粉丝 9
获赞 227

线程是依赖于进程存在的,所以要想了解线程必须先了解什么是进程。

1.概念

进程:打开任务管理器,正在运行的程序都会出现进程,所以进程指的就是正在运行(进行)的程序
多进程:多个进程同时运行,比如计算机可以一边玩游戏一边听音乐
线程和多线程:在同一个进程内可以执行多个任务,而这每一个任务我就可以看成是一个线程,线程是程度的执行单元,执行路径,是程序使用CPU的最基本单位。如果程序有多条执行路径就叫做多线程

2.意义:

多进程:可以提高CPU的使用率
多线程:可以提高程序的使用率,程序的执行其实都是在抢CPU的资源,不能保证哪个线程会先抢到资源,所以线程的执行有随机性。

3.多线程的实现方案

A:继承Thread 

B.实现Runnable接口

切记:run()方法里面的代码全部执行完毕,当前线程就会自动关闭销毁。
知道这一点以后要想关闭线程就知道怎么操作了

图片描述

4.线程的调度和优先级问题

A:线程的调度
    a:分时调度
    所有线程轮流使用CPU的使用权,平均分配每个线程的时间片
    b:抢占式调度
    优先让优先级高的线程使用CPU,优先级高的线程获取CPU时间片的几率相对高一些,如果线程的优先级相同,会随机选择一个。 
    java使用的是抢占式调度模型。

B:优先级

默认是5,范围是1-10

5.线程的控制(常见方法)

线程休眠(sleep)
加入线程(join)
礼让线程(yield)
守护线程(setDaemon)
中断线程(interrupt)

6.线程的生命周期
图片描述

7.多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)

A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据

8.同步解决线程安全问题

同步的前提:1.多个线程     2.多个线程使用的是同一个锁对象
A:同步代码块
    synchronized(对象) {
        需要被同步的代码;
    }       
    这里的锁对象可以是任意对象。          
B:同步方法
    把同步加在方法上。   
    这里的锁对象是this 
C:静态同步方法
    把同步加在方法上。       
    这里的锁对象是当前类的字节码文件对象(也就是类.class)

9.线程安全的类

通过源码查看到这些类里面的方法都加了同步锁,所以是线程安全的
A:StringBuffer
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。

10.线程死锁问题

是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象。如果出现了同步嵌套,就容易产生死锁问题。

11.线程之间的通信(生产者与消费者的案例)

线程之间的通信指的是针对同一个资源的操作有不同种类的线程

 举例:生产者做包子,消费者买包子。
此案例加入了两点优化:
A:等待唤醒机制
1.针对的是锁对象,所以锁对象是谁,就用谁调用wait和notify
2.wait,线程等待,释放锁
3.notify,正在等待的线程被唤醒
B:将同步锁代码块改成同步锁方法
很多人初级接触多线程时,会习惯把wait()和notify()放在run()方法里,一定    要谨记,这两个方法属于某个对象,应在对象所在的类方法中定义它,然后run中去调用它。另外wait()和notify()必须包括在synchronized代码块中。
package Thread.BaoZiPro;
//这是生产者类线程(生产包子)
public class Set implements Runnable {
    private int i;
    private Baozi bz;
    public Set(Baozi bz) {
        this.bz =bz;
    }
    @Override
    public void run() {
        while(true){
                if(i%2==0){
                    bz.setNum(100, "糖包子");
                }else{
                    bz.setNum(200, "肉包子");
                }
                i++;
            }
    }

}
package Thread.BaoZiPro;
//这是消费者类线程(购买包子)
public class Get implements Runnable {
    private Baozi bz;
    public Get(Baozi bz) {
        this.bz =bz;
    }

    @Override
    public void run() {
        while(true){
            bz.get();
        }
    }

}
package Thread.BaoZiPro;
//这是共享资源类
public class Baozi {
    private int num;
    private String type;    
    //设置一个标签判断是否有资源,默认值false
    private boolean flag;
    public synchronized void setNum(int num,String type) {
        //如果flag=true,表示有包子
        if(flag){
            try {
                this.wait();//生产者线程等待,并释放锁,等待被唤醒
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //如果如果flag=true,表示没有包子,则生产包子
        this.num = num;
        this.type= type;
        //并设置标签为true,提示有包子了
        flag=true;
        //唤醒正在等待的线程,也就是唤醒消费者线程
        this.notify();

}
    public synchronized void get() {
        //如果!flag=true,也就是flag=flase,没有包子
            if(!flag){
                try {
                    this.wait();//消费者线程等待,并释放锁,等待被唤醒
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            //如果!flag=false,也就是flag=true,有包子,所以消费者购买
            System.out.println(this.num+this.type);
            //设置共享资源标签为false,表示包子买完了
            flag=false;
            //唤醒正在等待的线程,也就是唤醒生产者线程
            this.notify();
    }

}
package Thread.BaoZiPro;
//这是测试类
public class BaoziDemo {

    public static void main(String[] args) {

        Baozi bz=new Baozi();
        Set set=new Set(bz);
        Get get=new Get(bz);
        Thread t1=new Thread(set);  
        Thread t2=new Thread(get);
        t2.start();
        t1.start();
    }

}

12.线程组

线程组表示的多个线程的集合
1.创建一个线程租
    ThreadGroup tG=new ThreadGroup(String name);                name表示的该线程组的名称

2.设置一个线程所在的线程组
    Thread t1=new Thread(tG, tg);
    Thread t2=new Thread(tG,tg2);
            这样就可把t1,t2两个线程放进线程组tG中
3.getThreadGroup 返回值是该线程所在线程组 
4.getThreadGroup.getName返回的是该线程所在线程组的名字

13.线程池

Executors类包含了一些返回线程池的方法:
1.public static ExecutorService newCachedThreadPool()  带缓冲的线程池
2.public static ExecutorService newFixedThreadPool(int nThreads) 可重用固定线程数的线程池
3.public static ExecutorService newSingleThreadExecutor() 单个线程的Executor

调用这些方法会返回一个ExecutorService对象,该对象表示一个线程池。
线程池对象可以通过调用submit()方法来执行Runnable对象或者Callable对象代表的线程,相当于线程的创建并启动。

14.定时器

定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能

实现一个定时器的步骤:
1.创建定时器对象
2.创建一个任务
3.通过定时器调度任务
打开App,阅读手记
10人推荐
发表评论
随时随地看视频慕课网APP

热门评论

好棒棒棒棒棒棒棒棒棒啊

查看全部评论