Java 11 线程

线程

进程

实际就是程序的执行过程

特点

1/独立性,每个进程都有自己的空间,在没有经过进程本身允许的情况下,一个进程不可以直接访问其他二点进程空间
2/动态性:是动态产生,动态消亡的
3/并发性:任何进程都可以和其他的进程一起并发执行

并发与并行

并行:多个指令在多个cpu上同时执行
并发:多个指令在单个cpu上交替执行

多进程同时执行

对于一个cpu而言,他是在多个进程间轮换执行的
也可以说是例如微信qq一块运行,实际上是给微信用一会,qq用一会,只不过运行的十分快,
当然现在是多核的

线程

进程可以同时执行多个任务,每个任务就是线程
进程当中的任务

多线程意义

因为现在处理器的核心越来越多,现在大多数计算机都比以往更擅长并行运算

例如二核四线程
就会存在并行操作
1.提高执行的效率
2.同时处理多个任务***

java开启线程的方式

继承Thread类
实现Runnable接口
实现Callable接口

Thread

案例

package com.ithema.o2;

public class DOME {
    /*
    *   1.继承一个类继承Thread
    *   2.重写run方法
    *   3.将线程任务代码写在run方法里
    *   4.创建线程对象
    *   5.调用start方法开启线程
    * */
    public static void main(String[] args) {
        mytread mytread = new mytread();
        mytread m1 = new mytread();
        mytread m2 = new mytread();
        m1.start();
        m2.start();
    }
}

class mytread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(i);
        }
    }
}
注意,只有调用了start方法,才是开启了线程的;
会发现打印的语句有错乱的现象!!

注意

java程序默认是多线程的,程序开启后会默认存在两个线程
1.主线程
2.垃圾回收线程
//当一些程序被默认为垃圾的时候,并且垃圾也比较多的时候,就会被清理

Runnable接口

扩展性更强,因为是接口

案例

package com.ithema.o2;

public class a1 {
    /* 1.编写一个类实现Runnable接口
        2.重写run方法
        3.将线程任务代码写在run方法里面
        4.创建线程资源对象
        5.创建线程资源,将资源写入
        6.使用线程对象调用start方法,开启线程
    * */
    public static void main(String[] args) {
        myrunnable m1=new myrunnable();
        m1.run();
        //创建线程对象,将资源放入
        Thread t1=new Thread(m1);
        //使用线程对象调用start方法,开启线程
        t1.start();
        for (int i=1;i<=100;i++){
            System.out.println(i);
        }
    }
}
class myrunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <= 330; i++) {
            System.out.println(i);
        }
    }
}

Callable接口

会有返回值

案例

package com.ithema.o2;

import java.util.Scanner;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class a2 {
    /*
        1.编写一个类实现Callable接口
        2.重写call方法
        3.将线程任务写在call方法里
    * */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程的任务资源对象
        clallable m1=new clallable();

        //创建线程任务对象
        FutureTask<Integer>task=new FutureTask<>(m1);

        //创建线程对象,传入任务资源
        Thread thread=new Thread(task);
        thread.start();

		//接受返回值
		//一定要在返回值之前打开这个get,否者线程都没开,又怎么会有结果呢
        Integer m3= task.get();
    }
}
class clallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for(int i=1;i<=1000;i++){
            System.out.println(i);
            sum=sum+i;

        }
        return sum;
    }
}

注意,因为有返回值,我们需要加上泛型,也就是需要什么就加上需要的那个返回值对象

需要一个中介值FutureTask

线程的相关方法

Thread类中的名字

getName
获取名字
setName
设置线程的名字
当然不仅仅又这样的一种方法,还有构造方法*
currentThread
获取当前的对象
注意Runnale实现的是接口的,所以不可以调用名字
sleep
public static void sleep(long time);
让当前线程休眠一会
线程的调度方式
抢占式调度(随机)
也就是java目前的
我们可以设置setPriority(int x);设置线程的优先级,1-10,默认为5;
getPriority();得到优先级
非抢占式调度

设置优先级并不是说先让某个线程先执行完,而是提高他的被给予资源的概率
setDaemon
设置为守护线程
当其他线程结束的时候就会不动了
但不是瞬间就结束

线程的安全和同步

案例

某电影场正在上映动画片,共有100张票,而他共有三个接口,请设置一个程序模拟该电影票卖票
-多线程共享操作同一份数据的时候,就会出现不安全的问题
package com.ithema.o2;

public class a3 {
    public static void main(String[] args) {
        Thread a1=new Thread(new thread(),"号码1:");
        Thread a2=new Thread(new thread(),"号码2:");
        Thread a3=new Thread(new thread(),"号码3:");
        a1.start();
        a2.start();
        a3.start();
    }
}
class thread implements Runnable {
    private int sum=100;
    @Override
    public void run() {
        while(true){
            if(sum<0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+sum+"号票");
            sum--;
        }

    }
}

问题

运行上述代码的时候,我们会发现程序会将一些相同的票卖出
这个问题实际上就是,线程的并发性,在线程1没有将该线程的该语句执行完的时候,就让处理器去执行另外一个线程了,就造成了这种问题
处理方式就是加上锁

解决

同步代码块
synchronized(锁对象){
	多条语句操作的共享数据的代码
}
注意一点,需要的是同一把锁,需要加上static,或者是,只写一个对象
最好用类的字节码问价
锁对象可以是任意对象,但是需要保证多条线程的锁对象,是同一把锁
同步可以解决多线的数据安全问题,但是也会降低程序的运行效率
同步方法
public synchronized void fangfa(){

}
//这样线程里面的东西就都是同步的了
面试
实际上这样写出来的锁对象也会有锁对象
静态方法:类的字节码对象   lei.class返回的是当前的字节码文件
非静态方法:this

Lock锁

使用Lock锁,
为接口,无法直接进行使用,创建他的子类ReenreantLock即可
例如
创建的为lock
lock.lock();
lock.unlock();
将需要锁上的元素放到这里面即可
记得把锁进行关闭,否则程序结束不了

死锁

介于两个或者多个线程互相持有对方所需要的资源
导致这些线程处于等待状态,无法继续前往执行

产生死锁的情况:同步嵌套

线程通信

1.确保线程能够按照预定的顺序执行,并且能够安全地访问共享资源
2.使得多条线程更好的进行协同工作

等待唤醒机制

案例
void wait();//当前对象等待
void notify();//随机唤醒某个对象
为锁对象的类型,就跟上面一样,锁对象一般只有两个字节码class和this
注意:notify是随机唤醒,记住,是随机唤醒
所以还有notifyAll();
唤醒所有的线程
该案例效率过低,不需要进行记忆
sleep方法和wait方法的区别
sleep是线程休眠,时间到了会自动醒来,并且不会释放锁
wait方法是线程等待,需要有其他线程进行notify唤醒,并且会释放锁
案例的效率提高

生产者消费者模式

主要包含了两类线程
生产者线程
消费者线程

介绍

建立一个中间的类,
就相当于判断中间的类的状态,为true时开启生产的,关闭消费的,false则相反
为了处理他们之间的关系,通常会采取共享的数据区域(缓存区),就像是一个仓库,生产生产完餐品之后放到生产区,不需要关心消费者,对于生产者也是一样的

线程的生命周期

面试

调用start方法启动线程对象
就绪:有执行资格,没有执行权
运行:抢到cpu执行权,有执行资格,有执行权
run:死亡,线程死亡,变成垃圾

在运行的时候,可能会遇到:计时等待(sleep),无限等待(wait),阻塞(没有执行资格,没有执行权);

线程池

介绍

池里均为线程的对象
线程创建一个线程的成本比较高,因为他涉及到与系统的交互,因为相当于来了个任务,我现创建对象
线程池就相当于养着一些对象
线程资源必须通过线程池维护,不允许在应用中自行显示

jdk默认的线程池

package com.ithema.o2;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class a4 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for(int i = 0; i < 10; i++){
            pool.submit(new Runnable(){
                @Override
                public void run() {
                    System.out.println("提交的任务");
                }
            });
        }
        
        pool.shutdown();
                
    }
}
创建一个线程池子对象,往里面放入线程池,但是默认的存入21亿个线程对象
这样可以指定养多少个线程,但是他底层的代码已经把线程的一些数据写死了,并不适合我们去写
ExecutorService pool = Executors.newCachedThreadPool(int x);

自定义线程池

package com.ithema.o2;

import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class a5{
    public static void main(String args[]){
        /* 参数1:核心线程的数量(正式员工);
            参数2:指定最大线程的数量(临时+正式);
            参数3:空闲时间,时间到了删除临时,也就是被销毁
            参数4:时间单位
            参数5:任务队列(指定排队人数)
            //有界队列
            //无界队列(最大为int的最大值)
            参数6:线程对象的任务工厂:
            参数7:拒绝策略
        * */
        ThreadPoolExecutor pool =new ThreadPoolExecutor(
          2,
          5,
          60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),//任务拍的队列
                Executors.defaultThreadFactory(),//默认的工场一般都是这个
                new ThreadPoolExecutor.AbortPolicy()//丢弃最新提交的任务,并且报高异常
        );
        for(int i=0;i<14;i++){
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"提交了了任务");
                }
            });
        }
    }

}
//临时线程什么适合会进行创建
//什么时候会,进行销毁

一些拒绝策略

一般只会使用第一个

单例设计模式

单例指的是单个实例,保证类的对象在内存中只有一份

使用场景

创建一个对象需要消耗的资源过多,比如io与数据库的链接
并且这个对象是可以进行复用的,我们可以设置为单例设计对象

使用

饿汉式
package com.ithema.o2;

public class a6 {
    public static void main(String[] args) {
        Single1 s1=Single1.getInstance();
        
        
    }
}
//单例设计对象:饿汉版
class Single1{
    private Single1(){

    }
    private static Single1 s = new Single1();
    public static Single1 getInstance(){
        return s;
    }
}


懒汉式(延长加载模式)
package com.ithema.o2;

public class a7 {
    public static void main(String[] args) {
        Single2 s1=Single2.getInstance();
        Single2 s2=Single2.getInstance();
        System.out.println(s1==s2);
    }
}
class Single2{
    private Single2(){};
    private  static Single2 s;
    public static Single2 getInstance(){
        if(s==null){
            s=new Single2();
        }

        return s;
    }

}
相对于上一个,相当于什么时候需要再创建
但是这种写法
在线程并发的时候,可能会创建多个线程时,就是在创建的时候,还没有进行创建执行权就被抢走了
所以我们对需要执行的代码进行上锁就可以了
package com.ithema.o2;

public class a7 {
    public static void main(String[] args) {
        Single2 s1=Single2.getInstance();
        Single2 s2=Single2.getInstance();
        System.out.println(s1==s2);
    }
}
class Single2{
    private Single2(){};
    private  static Single2 s;
    public static Single2 getInstance(){
        //这边加上null的原因是提高线程的效率,不会被一直阻塞
        if(s==null){
            synchronized (Single2.class){
                if(s==null){
                    s = new Single2();
                }
            }
        }
        return s;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值